Skip to main content

xitca_web/
body.rs

1//! http body types and traits.
2
3pub use xitca_http::body::{
4    Body, BodyExt, BoxBody, Empty, Frame, Full, RequestBody, ResponseBody, SizeHint, StreamBody, StreamDataBody,
5    Trailers,
6};
7
8pub(crate) use xitca_http::body::Either;
9
10use core::any::Any;
11
12use crate::{bytes::Bytes, error::BodyError};
13
14/// an extended trait for [Stream] that specify additional type info of the [Stream::Item] type.
15pub trait BodyStream: Body<Data: Into<Bytes> + AsRef<[u8]> + 'static, Error: Into<BodyError>> {}
16
17impl<B> BodyStream for B
18where
19    B: Body,
20    B::Data: Into<Bytes> + AsRef<[u8]> + 'static,
21    B::Error: Into<BodyError>,
22{
23}
24
25// conditional boxing body to convert generic body type to conrete
26pub(crate) fn downcast_body<B: BodyStream + 'static>(body: B) -> RequestBody {
27    let body = &mut Some(body);
28    match (body as &mut dyn Any).downcast_mut::<Option<RequestBody>>() {
29        Some(body) => body.take().unwrap(),
30        None => RequestBody::Boxed(BoxBody::new(body.take().unwrap())),
31    }
32}
33
34#[cfg(feature = "nightly")]
35pub use nightly::AsyncBody;
36
37#[cfg(feature = "nightly")]
38mod nightly {
39    use core::{
40        async_iter::AsyncIterator,
41        pin::Pin,
42        task::{Context, Poll},
43    };
44
45    use pin_project_lite::pin_project;
46
47    use crate::{body::Frame, bytes::Bytes};
48
49    use super::*;
50
51    pin_project! {
52        pub struct AsyncBody<B> {
53            #[pin]
54            inner: B
55        }
56
57    }
58
59    impl<B, T, E> From<B> for AsyncBody<B>
60    where
61        B: AsyncIterator<Item = Result<T, E>> + 'static,
62        E: Into<BodyError>,
63        Bytes: From<T>,
64    {
65        fn from(inner: B) -> Self {
66            Self { inner }
67        }
68    }
69
70    impl<B, T, E> Body for AsyncBody<B>
71    where
72        B: AsyncIterator<Item = Result<T, E>>,
73        Bytes: From<T>,
74    {
75        type Data = Bytes;
76        type Error = E;
77
78        #[inline]
79        fn poll_frame(
80            self: Pin<&mut Self>,
81            cx: &mut Context<'_>,
82        ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
83            AsyncIterator::poll_next(self.project().inner, cx).map_ok(|data| Frame::Data(data.into()))
84        }
85    }
86}