areq_body/
body.rs

1use {
2    bytes::{Buf, Bytes, BytesMut},
3    futures_lite::prelude::*,
4    std::{
5        convert::Infallible,
6        future,
7        io::{Cursor, Error, ErrorKind},
8        marker::PhantomData,
9        mem,
10        ops::DerefMut,
11        pin::Pin,
12        task::{Context, Poll},
13    },
14};
15
16#[cfg(feature = "rtn")]
17pub use crate::body_rtn::{SendBody, SendBodyExt};
18
19/// Type representing the body of an HTTP request/response.
20pub trait Body {
21    /// Type of the body data chunk.
22    type Chunk: Buf;
23
24    /// Asynchronously retrieves a body data chunk.
25    ///
26    /// Returns `Some(Ok(_))` when data is successfully received.
27    /// If an I/O error occurs, it is returned as `Some(Err(_))`.
28    /// When the entire body has been received, a returned `None`
29    /// indicates the end of the data stream.
30    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>>;
31
32    /// Returns a size [hint](Hint) for the body.
33    fn size_hint(&self) -> Hint;
34}
35
36/// Body size hint.
37///
38/// Used to indicate a kind and size of the request/response body.
39#[derive(Clone, Copy, Debug)]
40pub enum Hint {
41    /// The body is empty.
42    Empty,
43
44    /// The entire body is returned in a single
45    /// [`chunk`](Body::chunk) call.
46    ///
47    /// For this variant, an HTTP/1.1 client sets the
48    /// `Content-Length` header for the request.
49    Full {
50        /// Specifies the body size in bytes, if possible.
51        /// If the size cannot be determined in advance, this
52        /// field must be `None`.
53        len: Option<u64>,
54    },
55
56    /// The body is chunked and received through sequential
57    /// [`chunk`](Body::chunk) calls.
58    ///
59    /// For this variant, an HTTP/1.1 client sets the
60    /// `Transfer-Encoding: chunked` header for the request.
61    Chunked {
62        /// Indicates the end of the body stream.
63        end: bool,
64    },
65}
66
67impl Hint {
68    /// Returns `true` if the hint is [`Empty`](Hint::Empty).
69    #[inline]
70    pub fn is_empty(self) -> bool {
71        matches!(self, Self::Empty)
72    }
73
74    /// Returns `true` if the hint is [`Full`](Hint::Full).
75    #[inline]
76    pub fn is_full(self) -> bool {
77        matches!(self, Self::Full { .. })
78    }
79
80    /// Returns `true` if the hint is [`Chunked`](Hint::Chunked).
81    #[inline]
82    pub fn is_chunked(self) -> bool {
83        matches!(self, Self::Chunked { .. })
84    }
85
86    /// Checks if the body data stream has ended.
87    #[inline]
88    pub fn end(self) -> bool {
89        match self {
90            Self::Empty => true,
91            Self::Full { len } => len == Some(0),
92            Self::Chunked { end } => end,
93        }
94    }
95
96    /// Returns size as `Some` value or `None` if it's unknown.
97    #[inline]
98    pub fn size(self) -> Option<u64> {
99        match self {
100            Self::Empty => Some(0),
101            Self::Full { len } => len,
102            Self::Chunked { end } => {
103                if end {
104                    Some(0)
105                } else {
106                    None
107                }
108            }
109        }
110    }
111}
112
113/// A non-existent [buffer](Buf) for implementing an empty body.
114pub enum Void {}
115
116impl Buf for Void {
117    #[inline]
118    fn remaining(&self) -> usize {
119        match *self {}
120    }
121
122    #[inline]
123    fn chunk(&self) -> &[u8] {
124        match *self {}
125    }
126
127    #[inline]
128    fn advance(&mut self, _: usize) {
129        match *self {}
130    }
131}
132
133impl<B> Body for &mut B
134where
135    B: Body,
136{
137    type Chunk = B::Chunk;
138
139    #[inline]
140    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
141        (**self).chunk().await
142    }
143
144    #[inline]
145    fn size_hint(&self) -> Hint {
146        (**self).size_hint()
147    }
148}
149
150impl Body for () {
151    type Chunk = Void;
152
153    #[inline]
154    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
155        None
156    }
157
158    #[inline]
159    fn size_hint(&self) -> Hint {
160        Hint::Empty
161    }
162}
163
164impl<'slice> Body for &'slice [u8] {
165    type Chunk = &'slice [u8];
166
167    #[inline]
168    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
169        if self.is_empty() {
170            None
171        } else {
172            Some(Ok(mem::take(self)))
173        }
174    }
175
176    #[inline]
177    fn size_hint(&self) -> Hint {
178        Hint::Full {
179            len: Some(self.len() as u64),
180        }
181    }
182}
183
184impl<'str> Body for &'str str {
185    type Chunk = &'str [u8];
186
187    #[inline]
188    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
189        if self.is_empty() {
190            None
191        } else {
192            let s = mem::take(self);
193            Some(Ok(s.as_bytes()))
194        }
195    }
196
197    #[inline]
198    fn size_hint(&self) -> Hint {
199        Hint::Full {
200            len: Some(self.len() as u64),
201        }
202    }
203}
204
205impl Body for String {
206    type Chunk = Cursor<Self>;
207
208    #[inline]
209    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
210        if self.is_empty() {
211            None
212        } else {
213            let s = mem::take(self);
214            Some(Ok(Cursor::new(s)))
215        }
216    }
217
218    #[inline]
219    fn size_hint(&self) -> Hint {
220        Hint::Full {
221            len: Some(self.len() as u64),
222        }
223    }
224}
225
226impl Body for Vec<u8> {
227    type Chunk = Cursor<Self>;
228
229    #[inline]
230    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
231        if self.is_empty() {
232            None
233        } else {
234            let s = mem::take(self);
235            Some(Ok(Cursor::new(s)))
236        }
237    }
238
239    #[inline]
240    fn size_hint(&self) -> Hint {
241        Hint::Full {
242            len: Some(self.len() as u64),
243        }
244    }
245}
246
247impl<B> Body for Option<B>
248where
249    B: Body,
250{
251    type Chunk = B::Chunk;
252
253    #[inline]
254    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
255        match self {
256            Some(body) => body.chunk().await,
257            None => None,
258        }
259    }
260
261    #[inline]
262    fn size_hint(&self) -> Hint {
263        match self {
264            Some(body) => body.size_hint(),
265            None => Hint::Empty,
266        }
267    }
268}
269
270impl Body for Infallible {
271    type Chunk = Void;
272
273    #[inline]
274    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
275        match *self {}
276    }
277
278    #[inline]
279    fn size_hint(&self) -> Hint {
280        match *self {}
281    }
282}
283
284impl Body for Bytes {
285    type Chunk = Self;
286
287    #[inline]
288    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
289        if self.is_empty() {
290            None
291        } else {
292            let s = mem::take(self);
293            Some(Ok(s))
294        }
295    }
296
297    #[inline]
298    fn size_hint(&self) -> Hint {
299        Hint::Full {
300            len: Some(self.len() as u64),
301        }
302    }
303}
304
305/// Returns the full body from a [buffer](Buf).
306///
307/// # Example
308///
309/// ```
310/// # futures_lite::future::block_on(async {
311/// use areq_body::{Body, Full};
312///
313/// let mut body = Full::new("hello".as_bytes());
314/// let Some(Ok(chunk)) = body.chunk().await else {
315///     unreachable!();
316/// };
317///
318/// assert_eq!(chunk, "hello".as_bytes());
319/// assert!(body.chunk().await.is_none());
320/// # });
321/// ```
322pub struct Full<B>(Option<B>);
323
324impl<B> Full<B> {
325    /// Creates a body from the given [buffer](Buf).
326    #[inline]
327    pub const fn new(body: B) -> Self {
328        Self(Some(body))
329    }
330}
331
332impl<B> Body for Full<B>
333where
334    B: Buf,
335{
336    type Chunk = B;
337
338    #[inline]
339    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
340        self.0.take().map(Ok)
341    }
342
343    #[inline]
344    fn size_hint(&self) -> Hint {
345        Hint::Full {
346            len: Some(
347                self.0
348                    .as_ref()
349                    .map(|b| b.remaining() as u64)
350                    .unwrap_or_default(),
351            ),
352        }
353    }
354}
355
356/// Defers the full body from a [future](Future).
357///
358/// # Example
359///
360/// ```
361/// # futures_lite::future::block_on(async {
362/// use areq_body::{Body, Deferred};
363///
364/// let mut body = Deferred::new(Box::pin(async {
365///     Ok("hello".as_bytes())
366/// }));
367///
368/// let Some(Ok(chunk)) = body.chunk().await else {
369///     unreachable!();
370/// };
371///
372/// assert_eq!(chunk, "hello".as_bytes());
373/// assert!(body.chunk().await.is_none());
374/// # });
375/// ```
376pub struct Deferred<F>(Option<F>);
377
378impl<F> Deferred<F> {
379    #[inline]
380    pub fn new<U>(fu: U) -> Self
381    where
382        U: IntoFuture<IntoFuture = F>,
383    {
384        Self(Some(fu.into_future()))
385    }
386}
387
388impl<F, I> Body for Deferred<F>
389where
390    F: Future<Output = Result<I, Error>> + Unpin,
391    I: Buf,
392{
393    type Chunk = I;
394
395    #[inline]
396    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
397        match &mut self.0 {
398            Some(fu) => {
399                let mut fu = Pin::new(fu);
400                let res = future::poll_fn(|cx| fu.as_mut().poll(cx)).await;
401                self.0 = None;
402                Some(res)
403            }
404            None => None,
405        }
406    }
407
408    #[inline]
409    fn size_hint(&self) -> Hint {
410        Hint::Full {
411            len: if self.0.is_none() { Some(0) } else { None },
412        }
413    }
414}
415
416/// The chunked body from a [stream](Stream).
417///
418/// # Example
419///
420/// ```
421/// # futures_lite::future::block_on(async {
422/// use {
423///     areq_body::{Body, Chunked},
424///     futures_lite::stream,
425/// };
426///
427/// let mut body = Chunked(
428///     stream::iter(["h", "i"].map(|s| Ok(s.as_bytes())))
429/// );
430///
431/// let Some(Ok(chunk)) = body.chunk().await else {
432///     unreachable!();
433/// };
434///
435/// assert_eq!(chunk, "h".as_bytes());
436///
437/// let Some(Ok(chunk)) = body.chunk().await else {
438///     unreachable!();
439/// };
440///
441/// assert_eq!(chunk, "i".as_bytes());
442/// assert!(body.chunk().await.is_none());
443/// # });
444/// ```
445pub struct Chunked<S>(pub S);
446
447impl<S, I> Body for Chunked<S>
448where
449    S: Stream<Item = Result<I, Error>> + Unpin,
450    I: Buf,
451{
452    type Chunk = I;
453
454    #[inline]
455    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
456        self.0.next().await
457    }
458
459    #[inline]
460    fn size_hint(&self) -> Hint {
461        let (_, upper_bound) = self.0.size_hint();
462        Hint::Chunked {
463            end: upper_bound == Some(0),
464        }
465    }
466}
467
468/// A trait for converting into a [body](Body).
469pub trait IntoBody: Sized {
470    type Chunk: Buf;
471    type Body: Body<Chunk = Self::Chunk>;
472
473    fn into_body(self) -> Self::Body;
474}
475
476impl<B> IntoBody for B
477where
478    B: Body,
479{
480    type Chunk = B::Chunk;
481    type Body = Self;
482
483    #[inline]
484    fn into_body(self) -> Self::Body {
485        self
486    }
487}
488
489/// The poll based [body](Body) trait.
490///
491/// This trait is typically used to represent something
492/// similar to `dyn Body`, since the [`Body`] trait itself
493/// is not compatible with `dyn`. Instead, you can convert
494/// any body into [`PollBody`] using
495/// [`into_poll_body`](BodyExt::into_poll_body).
496///
497/// # Example
498///
499/// ```
500/// # futures_lite::future::block_on(async {
501/// use {
502///     areq_body::{Body, BodyExt, PollBody},
503///     std::future,
504/// };
505///
506/// let mut poll_body = Box::pin("uwu".into_poll_body());
507/// let body_future = future::poll_fn(|cx| poll_body.as_mut().poll_chunk(cx));
508/// let Some(Ok(chunk)) = body_future.await else {
509///     unreachable!();
510/// };
511///
512/// assert_eq!(chunk, "uwu".as_bytes());
513/// # });
514/// ```
515///
516/// A pinned `PollBody` implements the `Body` itself.
517/// So the example above can be simplified:
518///
519/// ```
520/// # futures_lite::future::block_on(async {
521/// use areq_body::{Body, BodyExt};
522///
523/// let mut poll_body = Box::pin("uwu".into_poll_body());
524/// let Some(Ok(chunk)) = poll_body.chunk().await else {
525///     unreachable!();
526/// };
527///
528/// assert_eq!(chunk, "uwu".as_bytes());
529/// # });
530/// ```
531///
532/// # Dyn Compatibility
533///
534/// Since `PollBody` is compatible with `dyn`, it allows erasing static `Body` types.
535/// To achieve this, you can use a helper method [`boxed_local`](BodyExt::boxed_local),
536/// which boxes any body into [`Pin<Box<dyn PollBody + '_>>`](BoxedLocal).
537///
538/// ```
539/// use areq_body::{Body, BodyExt};
540///
541/// enum Source<'src> {
542///     Binary(&'src [u8]),
543///     String(&'src str),
544/// }
545///
546/// fn body_from_source(src: Source<'_>) -> impl Body {
547///     match src {
548///         Source::Binary(s) => s.boxed_local(),
549///         Source::String(s) => s.boxed_local(),
550///     }
551/// }
552/// ```
553pub trait PollBody {
554    type Chunk: Buf;
555
556    fn poll_chunk(
557        self: Pin<&mut Self>,
558        cx: &mut Context<'_>,
559    ) -> Poll<Option<Result<Self::Chunk, Error>>>;
560
561    fn size_hint(&self) -> Hint;
562}
563
564impl<P> Body for Pin<P>
565where
566    P: DerefMut<Target: PollBody>,
567{
568    type Chunk = <P::Target as PollBody>::Chunk;
569
570    #[inline]
571    async fn chunk(&mut self) -> Option<Result<Self::Chunk, Error>> {
572        future::poll_fn(|cx| self.as_mut().poll_chunk(cx)).await
573    }
574
575    #[inline]
576    fn size_hint(&self) -> Hint {
577        self.as_ref().size_hint()
578    }
579}
580
581/// Alias for a boxed [body](PollBody).
582pub type BoxedLocal<'body, C = Bytes> = Pin<Box<dyn PollBody<Chunk = C> + 'body>>;
583
584impl<'body, C> Default for BoxedLocal<'body, C>
585where
586    C: Buf + 'body,
587{
588    fn default() -> Self {
589        Box::pin(empty())
590    }
591}
592
593/// Alias for a boxed thread-safe [body](PollBody).
594pub type Boxed<'body, C = Bytes> = Pin<Box<dyn PollBody<Chunk = C> + Send + 'body>>;
595
596impl<'body, C> Default for Boxed<'body, C>
597where
598    C: Buf + Send + 'body,
599{
600    fn default() -> Self {
601        Box::pin(empty())
602    }
603}
604
605fn empty<C>() -> impl PollBody<Chunk = C>
606where
607    C: Buf,
608{
609    struct Empty<C>(PhantomData<C>);
610
611    impl<C> PollBody for Empty<C>
612    where
613        C: Buf,
614    {
615        type Chunk = C;
616
617        fn poll_chunk(
618            self: Pin<&mut Self>,
619            _: &mut Context<'_>,
620        ) -> Poll<Option<Result<Self::Chunk, Error>>> {
621            Poll::Ready(None)
622        }
623
624        fn size_hint(&self) -> Hint {
625            Hint::Empty
626        }
627    }
628
629    Empty(PhantomData)
630}
631
632/// Extension methods for a [body](Body).
633pub trait BodyExt: IntoBody {
634    #[inline]
635    async fn take_full(self) -> Result<Option<Self::Chunk>, Error> {
636        let mut body = self.into_body();
637        let size = body.size_hint();
638
639        assert!(
640            matches!(size, Hint::Full { .. }),
641            "the body size must be full",
642        );
643
644        let chunk = body.chunk().await;
645
646        match &chunk {
647            Some(Ok(chunk)) => {
648                debug_assert!(
649                    !size.end() || !chunk.has_remaining(),
650                    "an empty body shouldn't have remaining chunks",
651                );
652            }
653            Some(Err(_)) => {}
654            None => debug_assert!(size.end(), "the body must be empty"),
655        }
656
657        debug_assert!(body.size_hint().end(), "the body must ends after the chunk");
658
659        chunk.transpose()
660    }
661
662    #[inline]
663    async fn text(self) -> Result<String, Error> {
664        let mut body = self.into_body();
665        let cap = body.size_hint().size().unwrap_or(1024);
666        let mut s = String::with_capacity(cap as usize);
667        while let Some(res) = body.chunk().await {
668            match str::from_utf8(res?.chunk()) {
669                Ok(chunk) => s.push_str(chunk),
670                Err(_) => {
671                    return Err(Error::new(
672                        ErrorKind::InvalidData,
673                        "stream did not contain valid UTF-8",
674                    ));
675                }
676            }
677        }
678
679        Ok(s)
680    }
681
682    #[inline]
683    async fn vec(self) -> Result<Vec<u8>, Error> {
684        let mut body = self.into_body();
685        let cap = body.size_hint().size().unwrap_or(1024);
686        let mut v = Vec::with_capacity(cap as usize);
687        while let Some(res) = body.chunk().await {
688            v.extend_from_slice(res?.chunk());
689        }
690
691        Ok(v)
692    }
693
694    #[inline]
695    async fn bytes(self) -> Result<Bytes, Error>
696    where
697        Self::Chunk: Into<Bytes>,
698    {
699        let bytes_mut = self.bytes_mut().await?;
700        Ok(bytes_mut.freeze())
701    }
702
703    #[inline]
704    async fn bytes_mut(self) -> Result<BytesMut, Error>
705    where
706        Self::Chunk: Into<Bytes>,
707    {
708        let mut out = BytesMut::new();
709        let mut body = self.into_body();
710        while let Some(res) = body.chunk().await {
711            match res?.into().try_into_mut() {
712                Ok(bytes_mut) => out.unsplit(bytes_mut),
713                Err(bytes) => out.extend_from_slice(&bytes),
714            }
715        }
716
717        Ok(out)
718    }
719
720    #[inline]
721    fn read(self) -> impl AsyncRead {
722        Reader {
723            body: self.into_poll_body(),
724            state: State::Start,
725        }
726    }
727
728    #[inline]
729    fn stream(self) -> impl Stream<Item = Result<Self::Chunk, Error>> {
730        Streamer {
731            body: self.into_poll_body(),
732        }
733    }
734
735    #[inline]
736    fn into_poll_body(self) -> impl PollBody<Chunk = Self::Chunk> {
737        unfold(self.into_body(), |mut body| async {
738            match body.chunk().await {
739                Some(res) => Step::Next { body, res },
740                None => Step::End(body),
741            }
742        })
743    }
744
745    #[inline]
746    fn boxed_local<'body>(self) -> BoxedLocal<'body, Self::Chunk>
747    where
748        Self: 'body,
749    {
750        Box::pin(self.into_poll_body())
751    }
752}
753
754impl<B> BodyExt for B where B: IntoBody {}
755
756enum Step<B, C> {
757    Next { body: B, res: Result<C, Error> },
758    End(B),
759}
760
761#[inline]
762fn unfold<B, F, U>(body: B, f: F) -> Unfold<B, F, U>
763where
764    B: Body,
765    F: FnMut(B) -> U,
766    U: Future<Output = Step<B, B::Chunk>>,
767{
768    Unfold {
769        body: Some(body),
770        f,
771        fu: None,
772    }
773}
774
775pin_project_lite::pin_project! {
776    struct Unfold<B, F, U> {
777        body: Option<B>,
778        f: F,
779        #[pin]
780        fu: Option<U>,
781    }
782}
783
784impl<B, F, U> PollBody for Unfold<B, F, U>
785where
786    B: Body,
787    F: FnMut(B) -> U,
788    U: Future<Output = Step<B, B::Chunk>>,
789{
790    type Chunk = B::Chunk;
791
792    #[inline]
793    fn poll_chunk(
794        self: Pin<&mut Self>,
795        cx: &mut Context<'_>,
796    ) -> Poll<Option<Result<Self::Chunk, Error>>> {
797        let mut me = self.project();
798        if let Some(body) = me.body.take() {
799            me.fu.set(Some((me.f)(body)));
800        }
801
802        let fu = me.fu.as_pin_mut().expect("future should always be here");
803
804        match fu.poll(cx) {
805            Poll::Ready(Step::Next { body, res }) => {
806                *me.body = Some(body);
807                Poll::Ready(Some(res))
808            }
809            Poll::Ready(Step::End(body)) => {
810                *me.body = Some(body);
811                Poll::Ready(None)
812            }
813            Poll::Pending => Poll::Pending,
814        }
815    }
816
817    #[inline]
818    fn size_hint(&self) -> Hint {
819        self.body
820            .as_ref()
821            .expect("called before the chunk retrieval was completed")
822            .size_hint()
823    }
824}
825
826pin_project_lite::pin_project! {
827     struct Reader<B, C> {
828        #[pin]
829        body: B,
830        state: State<C>,
831    }
832}
833
834impl<B> AsyncRead for Reader<B, B::Chunk>
835where
836    B: PollBody,
837{
838    #[inline]
839    fn poll_read(
840        self: Pin<&mut Self>,
841        cx: &mut Context<'_>,
842        buf: &mut [u8],
843    ) -> Poll<Result<usize, Error>> {
844        let mut me = self.project();
845
846        if let State::End = me.state {
847            return Poll::Ready(Ok(0));
848        }
849
850        if buf.is_empty() {
851            return Poll::Ready(Ok(0));
852        }
853
854        if !me.state.has_remaining() {
855            loop {
856                match me.body.as_mut().poll_chunk(cx) {
857                    Poll::Ready(Some(Ok(c))) => {
858                        if c.has_remaining() {
859                            *me.state = State::Next(c);
860                            break;
861                        }
862                    }
863                    Poll::Ready(Some(Err(e))) => return Poll::Ready(Err(e)),
864                    Poll::Ready(None) => {
865                        *me.state = State::End;
866                        return Poll::Ready(Ok(0));
867                    }
868                    Poll::Pending => return Poll::Pending,
869                }
870            }
871        }
872
873        let n = usize::min(me.state.remaining(), buf.len());
874        debug_assert_ne!(n, 0, "at least one byte must be read");
875
876        me.state.copy_to_slice(&mut buf[..n]);
877        Poll::Ready(Ok(n))
878    }
879}
880
881enum State<B> {
882    Start,
883    Next(B),
884    End,
885}
886
887impl<B> Buf for State<B>
888where
889    B: Buf,
890{
891    #[inline]
892    fn remaining(&self) -> usize {
893        match self {
894            Self::Next(b) => b.remaining(),
895            Self::Start | Self::End => 0,
896        }
897    }
898
899    #[inline]
900    fn chunk(&self) -> &[u8] {
901        match self {
902            Self::Next(b) => b.chunk(),
903            Self::Start | Self::End => &[],
904        }
905    }
906
907    #[inline]
908    fn advance(&mut self, cnt: usize) {
909        match self {
910            Self::Next(b) => b.advance(cnt),
911            Self::Start | Self::End => debug_assert_eq!(cnt, 0, "can't advance further"),
912        }
913    }
914}
915
916pin_project_lite::pin_project! {
917    struct Streamer<B> {
918       #[pin]
919       body: B,
920   }
921}
922
923impl<B> Stream for Streamer<B>
924where
925    B: PollBody,
926{
927    type Item = Result<B::Chunk, Error>;
928
929    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
930        self.project().body.poll_chunk(cx)
931    }
932}
933
934#[cfg(test)]
935mod tests {
936    use {
937        super::*,
938        futures_lite::{future, stream},
939        std::{io::ErrorKind, pin, slice},
940    };
941
942    #[test]
943    fn slice() {
944        let src = "hi";
945        let actual = future::block_on(src.as_bytes().take_full()).expect("take full body");
946
947        assert_eq!(
948            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
949            src.as_bytes(),
950        );
951    }
952
953    #[test]
954    fn str() {
955        let src = "hi";
956        let actual = future::block_on(src.take_full()).expect("take full body");
957
958        assert_eq!(
959            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
960            src.as_bytes(),
961        );
962    }
963
964    #[test]
965    fn full() {
966        let src = "hi";
967        let full = Full::new(src.as_bytes());
968        let actual = future::block_on(full.take_full()).expect("take full body");
969
970        assert_eq!(
971            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
972            src.as_bytes(),
973        );
974    }
975
976    #[test]
977    fn deferred() {
978        let src = "hi";
979        let deferred = Deferred::new(future::ready(Ok(src.as_bytes())));
980        let actual = future::block_on(deferred.take_full()).expect("take full body");
981
982        assert_eq!(
983            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
984            src.as_bytes(),
985        );
986    }
987
988    #[test]
989    fn chunked() {
990        let src = [Ok("a"), Ok("b"), Err(Error::from(ErrorKind::UnexpectedEof))]
991            .map(|r| r.map(str::as_bytes));
992
993        let n = src.len();
994
995        let mut chunked = Chunked(stream::iter(src));
996        for _ in 0..n {
997            let actual = future::block_on(chunked.chunk());
998            match actual {
999                Some(Ok(a)) => assert!(matches!(a, b"a" | b"b")),
1000                Some(Err(e)) => assert_eq!(e.kind(), ErrorKind::UnexpectedEof),
1001                None => unreachable!(),
1002            }
1003        }
1004    }
1005
1006    #[test]
1007    fn text() {
1008        let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1009        let body = Chunked(stream::iter(src));
1010        let text = future::block_on(body.text()).expect("read body text");
1011        assert_eq!(text, "hello");
1012    }
1013
1014    #[test]
1015    fn vec() {
1016        let src = [1, 2, 3, 4].each_ref().map(slice::from_ref).map(Ok);
1017        let body = Chunked(stream::iter(src));
1018        let vec = future::block_on(body.vec()).expect("read body text");
1019        assert_eq!(vec, [1, 2, 3, 4]);
1020    }
1021
1022    #[test]
1023    fn bytes() {
1024        let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1025        let body = Chunked(stream::iter(src));
1026        let bytes = future::block_on(body.bytes()).expect("read body bytes");
1027        assert_eq!(bytes, "hello");
1028    }
1029
1030    #[test]
1031    fn bytes_mut() {
1032        let src = ["he", "ll", "o"].map(str::as_bytes).map(Ok);
1033        let body = Chunked(stream::iter(src));
1034        let bytes_mut = future::block_on(body.bytes_mut()).expect("read body bytes");
1035        assert_eq!(bytes_mut, "hello");
1036    }
1037
1038    #[test]
1039    fn read() {
1040        let src = ["h", "e", "ll", "o"].map(str::as_bytes).map(Ok);
1041        let body = Chunked(stream::iter(src));
1042        let mut reader = pin::pin!(body.read());
1043
1044        let mut out = String::new();
1045        let res = future::block_on(reader.read_to_string(&mut out));
1046        assert_eq!(res.ok(), Some(5));
1047        assert_eq!(out, "hello");
1048    }
1049
1050    #[test]
1051    fn read_partial() {
1052        let src = ["h", "e", "ll", "o"].map(str::as_bytes).map(Ok);
1053        let body = Chunked(stream::iter(src));
1054        let mut reader = pin::pin!(body.read());
1055
1056        for (size, part) in [
1057            (1, b"h\0"),
1058            (1, b"e\0"),
1059            (2, b"ll"),
1060            (1, b"o\0"),
1061            (0, b"\0\0"),
1062        ] {
1063            let mut buf = [0; 2];
1064            let n = future::block_on(reader.read(&mut buf)).expect("read body part to the buffer");
1065            assert_eq!(n, size);
1066            assert_eq!(&buf, part);
1067        }
1068    }
1069
1070    #[test]
1071    fn into_poll_body() {
1072        let src = "hi";
1073        let body = Full::new(src.as_bytes());
1074        let poll_body = pin::pin!(body.into_poll_body());
1075        let actual = future::block_on(poll_body.take_full()).expect("take full body");
1076
1077        assert_eq!(
1078            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1079            src.as_bytes(),
1080        );
1081    }
1082
1083    #[test]
1084    fn boxed_local() {
1085        let src = "hi";
1086        let body = Full::new(src.as_bytes());
1087        let boxed_body = body.boxed_local();
1088        let actual = future::block_on(boxed_body.take_full()).expect("take full body");
1089
1090        assert_eq!(
1091            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1092            src.as_bytes(),
1093        );
1094    }
1095
1096    #[cfg(feature = "rtn")]
1097    #[test]
1098    fn boxed() {
1099        let src = "hi";
1100        let body = Full::new(src.as_bytes());
1101        let boxed_body = body.boxed();
1102        let actual = future::block_on(boxed_body.take_full()).expect("take full body");
1103
1104        assert_eq!(
1105            actual.as_ref().map(Buf::chunk).unwrap_or_default(),
1106            src.as_bytes(),
1107        );
1108    }
1109}