Skip to main content

http_body_alt/
util.rs

1use core::{
2    convert::Infallible,
3    marker::PhantomData,
4    pin::Pin,
5    task::{Context, Poll},
6};
7
8use bytes::Buf;
9use futures_core::stream::Stream;
10use http::header::HeaderMap;
11use pin_project_lite::pin_project;
12
13use super::{body::Body, frame::Frame, size_hint::SizeHint};
14
15pin_project! {
16    /// A body that consists of a single chunk.
17    #[derive(Clone, Copy, Debug)]
18    pub struct Full<D> {
19        data: Option<D>,
20    }
21}
22
23impl<D> Full<D>
24where
25    D: Buf,
26{
27    /// Create a new `Full`.
28    #[inline]
29    pub const fn new(data: D) -> Self {
30        Self { data: Some(data) }
31    }
32}
33
34impl<D> Body for Full<D>
35where
36    D: Buf,
37{
38    type Data = D;
39    type Error = Infallible;
40
41    #[inline]
42    fn poll_frame(
43        mut self: Pin<&mut Self>,
44        _: &mut Context<'_>,
45    ) -> Poll<Option<Result<crate::Frame<Self::Data>, Self::Error>>> {
46        Poll::Ready(self.data.take().map(|d| Ok(Frame::Data(d))))
47    }
48
49    #[inline]
50    fn is_end_stream(&self) -> bool {
51        self.data.is_none()
52    }
53
54    #[inline]
55    fn size_hint(&self) -> SizeHint {
56        match self.data {
57            Some(ref data) => SizeHint::exact(data.remaining()),
58            None => SizeHint::None,
59        }
60    }
61}
62
63#[derive(Debug, Default, Clone, Copy)]
64pub struct Empty<D>(PhantomData<fn(D)>);
65
66impl<D> Empty<D> {
67    pub const fn new() -> Self {
68        Self(PhantomData)
69    }
70}
71
72impl<D> Body for Empty<D> {
73    type Data = D;
74    type Error = Infallible;
75
76    #[inline]
77    fn poll_frame(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
78        Poll::Ready(None)
79    }
80
81    #[inline]
82    fn is_end_stream(&self) -> bool {
83        true
84    }
85
86    #[inline]
87    fn size_hint(&self) -> SizeHint {
88        SizeHint::None
89    }
90}
91
92pin_project! {
93    pub struct Either<L, R> {
94        #[pin]
95        inner: EitherInner<L, R>
96    }
97}
98
99pin_project! {
100    #[project = EitherProj]
101    enum EitherInner<L, R> {
102        L {
103            #[pin]
104            inner: L
105        },
106        R {
107            #[pin]
108            inner: R
109        }
110    }
111}
112
113impl<L, R> Either<L, R> {
114    #[inline]
115    pub const fn left(inner: L) -> Self {
116        Self {
117            inner: EitherInner::L { inner },
118        }
119    }
120
121    #[inline]
122    pub const fn right(inner: R) -> Self {
123        Self {
124            inner: EitherInner::R { inner },
125        }
126    }
127
128    #[inline]
129    pub fn into_left(self) -> Result<L, Self> {
130        match self.inner {
131            EitherInner::L { inner } => Ok(inner),
132            inner => Err(Self { inner }),
133        }
134    }
135
136    #[inline]
137    pub fn into_right(self) -> Result<R, Self> {
138        match self.inner {
139            EitherInner::R { inner } => Ok(inner),
140            inner => Err(Self { inner }),
141        }
142    }
143}
144
145impl<L> Either<L, L> {
146    #[inline]
147    pub fn into_inner(self) -> L {
148        match self.inner {
149            EitherInner::L { inner } => inner,
150            EitherInner::R { inner } => inner,
151        }
152    }
153}
154
155impl<L, R> Body for Either<L, R>
156where
157    L: Body,
158    R: Body<Data = L::Data>,
159    R::Error: From<L::Error>,
160{
161    type Data = L::Data;
162    type Error = R::Error;
163
164    #[inline]
165    fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
166        match self.project().inner.project() {
167            EitherProj::L { inner } => inner.poll_frame(cx).map(|res| res.map(|res| res.map_err(Into::into))),
168            EitherProj::R { inner } => inner.poll_frame(cx),
169        }
170    }
171
172    #[inline]
173    fn is_end_stream(&self) -> bool {
174        match self.inner {
175            EitherInner::L { ref inner } => inner.is_end_stream(),
176            EitherInner::R { ref inner } => inner.is_end_stream(),
177        }
178    }
179
180    #[inline]
181    fn size_hint(&self) -> SizeHint {
182        match self.inner {
183            EitherInner::L { ref inner } => inner.size_hint(),
184            EitherInner::R { ref inner } => inner.size_hint(),
185        }
186    }
187}
188
189pin_project! {
190    /// Bidirectional adapter between [`Stream`] and [`Body`] at the [`Frame`] level:
191    /// - When the inner value implements [`Body`], this type implements [`Stream`] yielding
192    ///   `Result<Frame<Body::Data>, Body::Error>`.
193    /// - When the inner value implements [`Stream`], this type implements [`Body`] forwarding
194    ///   each `Result<Frame<D>, E>` frame as-is.
195    #[derive(Debug)]
196    pub struct StreamBody<T> {
197        #[pin]
198        pub(crate) value: T
199    }
200}
201
202impl<T> StreamBody<T> {
203    pub fn new(value: T) -> Self {
204        Self { value }
205    }
206}
207
208impl<S, D, E> Body for StreamBody<S>
209where
210    S: Stream<Item = Result<Frame<D>, E>>,
211{
212    type Data = D;
213    type Error = E;
214
215    #[inline]
216    fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
217        Stream::poll_next(self.project().value, cx)
218    }
219
220    #[inline]
221    fn is_end_stream(&self) -> bool {
222        false
223    }
224
225    #[inline]
226    fn size_hint(&self) -> SizeHint {
227        match Stream::size_hint(&self.value) {
228            (low, Some(up)) if low == up => SizeHint::exact(low),
229            SizeHint::NO_BODY_HINT => SizeHint::None,
230            _ => SizeHint::Unknown,
231        }
232    }
233}
234
235pin_project! {
236    /// Bidirectional adapter between [`Stream`] and [`Body`]:
237    /// - When the inner value implements [`Body`], this type implements [`Stream`] yielding
238    ///   `Result<Body::Data, Body::Error>`. Trailer frames are ignored and treated as end of stream.
239    /// - When the inner value implements [`Stream`], this type implements [`Body`] wrapping each
240    ///   streamed item into [`Frame::Data`].
241    #[derive(Debug)]
242    pub struct StreamDataBody<T> {
243        #[pin]
244        pub(crate) value: T
245    }
246}
247
248impl<T> StreamDataBody<T> {
249    pub fn new(value: T) -> Self {
250        Self { value }
251    }
252}
253
254impl<S, T, E> Body for StreamDataBody<S>
255where
256    S: Stream<Item = Result<T, E>>,
257{
258    type Data = T;
259    type Error = E;
260
261    #[inline]
262    fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
263        Stream::poll_next(self.project().value, cx).map_ok(Frame::Data)
264    }
265
266    #[inline]
267    fn is_end_stream(&self) -> bool {
268        false
269    }
270
271    #[inline]
272    fn size_hint(&self) -> SizeHint {
273        SizeHint::from_stream_size_hint(self.value.size_hint())
274    }
275}
276
277pin_project! {
278    pub struct Data<B> {
279        #[pin]
280        body: B
281    }
282}
283
284impl<B> Data<B>
285where
286    B: Body,
287{
288    pub fn new(body: B) -> Self {
289        Self { body }
290    }
291}
292
293impl<B> Body for Data<B>
294where
295    B: Body,
296{
297    type Data = B::Data;
298    type Error = B::Error;
299
300    #[inline]
301    fn poll_frame(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
302        match self.project().body.poll_frame(cx) {
303            Poll::Ready(Some(Ok(Frame::Trailers(_)))) => Poll::Ready(None),
304            res => res,
305        }
306    }
307
308    #[inline]
309    fn is_end_stream(&self) -> bool {
310        self.body.is_end_stream()
311    }
312
313    #[inline]
314    fn size_hint(&self) -> SizeHint {
315        self.body.size_hint()
316    }
317}
318
319pub struct Trailers<D> {
320    trailers: Option<HeaderMap>,
321    _data: PhantomData<fn(D)>,
322}
323
324impl<D> Trailers<D> {
325    pub fn new(trailers: HeaderMap) -> Self {
326        Self {
327            trailers: Some(trailers),
328            _data: PhantomData,
329        }
330    }
331}
332
333impl<D> Body for Trailers<D> {
334    type Data = D;
335    type Error = Infallible;
336
337    #[inline]
338    fn poll_frame(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
339        Poll::Ready(
340            self.get_mut()
341                .trailers
342                .take()
343                .map(|trailers| Ok(Frame::Trailers(trailers))),
344        )
345    }
346
347    #[inline]
348    fn is_end_stream(&self) -> bool {
349        self.trailers.is_none()
350    }
351
352    #[inline]
353    fn size_hint(&self) -> SizeHint {
354        SizeHint::None
355    }
356}