Skip to main content

http_body_util/
full.rs

1use bytes::{Buf, Bytes};
2use http_body::{Body, Frame, SizeHint};
3use pin_project_lite::pin_project;
4use std::borrow::Cow;
5use std::convert::{Infallible, TryFrom};
6use std::pin::Pin;
7use std::task::{Context, Poll};
8
9pin_project! {
10    /// A body that consists of a single chunk.
11    #[derive(Clone, Copy, Debug)]
12    pub struct Full<D> {
13        data: Option<D>,
14    }
15}
16
17impl<D> Full<D>
18where
19    D: Buf,
20{
21    /// Create a new `Full`.
22    pub fn new(data: D) -> Self {
23        let data = if data.has_remaining() {
24            Some(data)
25        } else {
26            None
27        };
28        Full { data }
29    }
30}
31
32impl<D> Full<D> {
33    /// Consumes this `Full`, returning the wrapped value.
34    ///
35    /// If this body has already been polled, this returns `None`.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// # use http_body_util::Full;
41    /// const DATA: &[u8] = b"hello";
42    /// let full = Full::new(DATA);
43    /// assert_eq!(full.into_inner(), Some("hello").map(str::as_bytes));
44    /// ```
45    pub fn into_inner(self) -> Option<D> {
46        self.data
47    }
48}
49
50impl<D> Body for Full<D>
51where
52    D: Buf,
53{
54    type Data = D;
55    type Error = Infallible;
56
57    fn poll_frame(
58        mut self: Pin<&mut Self>,
59        _cx: &mut Context<'_>,
60    ) -> Poll<Option<Result<Frame<D>, Self::Error>>> {
61        Poll::Ready(self.data.take().map(|d| Ok(Frame::data(d))))
62    }
63
64    fn is_end_stream(&self) -> bool {
65        self.data.is_none()
66    }
67
68    fn size_hint(&self) -> SizeHint {
69        self.data
70            .as_ref()
71            .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()))
72            .unwrap_or_else(|| SizeHint::with_exact(0))
73    }
74}
75
76impl<D> Default for Full<D>
77where
78    D: Buf,
79{
80    /// Create an empty `Full`.
81    fn default() -> Self {
82        Full { data: None }
83    }
84}
85
86impl<D> From<Bytes> for Full<D>
87where
88    D: Buf + From<Bytes>,
89{
90    fn from(bytes: Bytes) -> Self {
91        Full::new(D::from(bytes))
92    }
93}
94
95impl<D> From<Vec<u8>> for Full<D>
96where
97    D: Buf + From<Vec<u8>>,
98{
99    fn from(vec: Vec<u8>) -> Self {
100        Full::new(D::from(vec))
101    }
102}
103
104impl<D> From<&'static [u8]> for Full<D>
105where
106    D: Buf + From<&'static [u8]>,
107{
108    fn from(slice: &'static [u8]) -> Self {
109        Full::new(D::from(slice))
110    }
111}
112
113impl<D, B> From<Cow<'static, B>> for Full<D>
114where
115    D: Buf + From<&'static B> + From<B::Owned>,
116    B: ToOwned + ?Sized,
117{
118    fn from(cow: Cow<'static, B>) -> Self {
119        match cow {
120            Cow::Borrowed(b) => Full::new(D::from(b)),
121            Cow::Owned(o) => Full::new(D::from(o)),
122        }
123    }
124}
125
126impl<D> From<String> for Full<D>
127where
128    D: Buf + From<String>,
129{
130    fn from(s: String) -> Self {
131        Full::new(D::from(s))
132    }
133}
134
135impl<D> From<&'static str> for Full<D>
136where
137    D: Buf + From<&'static str>,
138{
139    fn from(slice: &'static str) -> Self {
140        Full::new(D::from(slice))
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147    use crate::BodyExt;
148
149    #[tokio::test]
150    async fn full_returns_some() {
151        let mut full = Full::new(&b"hello"[..]);
152        assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64));
153        assert_eq!(
154            full.frame().await.unwrap().unwrap().into_data().unwrap(),
155            &b"hello"[..]
156        );
157        assert!(full.frame().await.is_none());
158    }
159
160    #[tokio::test]
161    async fn empty_full_returns_none() {
162        assert!(Full::<&[u8]>::default().frame().await.is_none());
163        assert!(Full::new(&b""[..]).frame().await.is_none());
164    }
165
166    #[tokio::test]
167    async fn full_into_inner_returns_none_before_poll() {
168        const DATA: &[u8] = b"hello";
169        let full = Full::new(DATA);
170        assert_eq!(
171            full.into_inner(),
172            Some(str::as_bytes("hello")),
173            "`Full::into_inner()` returns `Some(_)` before poll"
174        );
175    }
176
177    #[tokio::test]
178    async fn full_into_inner_returns_none_after_poll() {
179        const DATA: &[u8] = b"hello";
180        let mut full = Full::new(DATA);
181        full.frame().await.expect("a result").expect("a frame");
182        assert_eq!(
183            full.into_inner(),
184            None,
185            "`Full::into_inner()` returns `None` after poll"
186        );
187    }
188}