http_body_util/
lib.rs

1#![deny(missing_debug_implementations, missing_docs, unreachable_pub)]
2#![cfg_attr(test, deny(warnings))]
3
4//! Utilities for [`http_body::Body`].
5//!
6//! [`BodyExt`] adds extensions to the common trait.
7//!
8//! [`Empty`] and [`Full`] provide simple implementations.
9
10mod collected;
11pub mod combinators;
12mod either;
13mod empty;
14mod full;
15mod limited;
16mod stream;
17
18mod util;
19
20use self::combinators::{BoxBody, MapErr, MapFrame, UnsyncBoxBody};
21
22pub use self::collected::Collected;
23pub use self::either::Either;
24pub use self::empty::Empty;
25pub use self::full::Full;
26pub use self::limited::{LengthLimitError, Limited};
27pub use self::stream::{BodyDataStream, BodyStream, StreamBody};
28
29/// An extension trait for [`http_body::Body`] adding various combinators and adapters
30pub trait BodyExt: http_body::Body {
31    /// Returns a future that resolves to the next [`Frame`], if any.
32    ///
33    /// [`Frame`]: combinators::Frame
34    fn frame(&mut self) -> combinators::Frame<'_, Self>
35    where
36        Self: Unpin,
37    {
38        combinators::Frame(self)
39    }
40
41    /// Maps this body's frame to a different kind.
42    fn map_frame<F, B>(self, f: F) -> MapFrame<Self, F>
43    where
44        Self: Sized,
45        F: FnMut(http_body::Frame<Self::Data>) -> http_body::Frame<B>,
46        B: bytes::Buf,
47    {
48        MapFrame::new(self, f)
49    }
50
51    /// Maps this body's error value to a different value.
52    fn map_err<F, E>(self, f: F) -> MapErr<Self, F>
53    where
54        Self: Sized,
55        F: FnMut(Self::Error) -> E,
56    {
57        MapErr::new(self, f)
58    }
59
60    /// Turn this body into a boxed trait object.
61    fn boxed(self) -> BoxBody<Self::Data, Self::Error>
62    where
63        Self: Sized + Send + Sync + 'static,
64    {
65        BoxBody::new(self)
66    }
67
68    /// Turn this body into a boxed trait object that is !Sync.
69    fn boxed_unsync(self) -> UnsyncBoxBody<Self::Data, Self::Error>
70    where
71        Self: Sized + Send + 'static,
72    {
73        UnsyncBoxBody::new(self)
74    }
75
76    /// Turn this body into [`Collected`] body which will collect all the DATA frames
77    /// and trailers.
78    fn collect(self) -> combinators::Collect<Self>
79    where
80        Self: Sized,
81    {
82        combinators::Collect {
83            body: self,
84            collected: Some(crate::Collected::default()),
85        }
86    }
87
88    /// Add trailers to the body.
89    ///
90    /// The trailers will be sent when all previous frames have been sent and the `trailers` future
91    /// resolves.
92    ///
93    /// # Example
94    ///
95    /// ```
96    /// use http::HeaderMap;
97    /// use http_body_util::{Full, BodyExt};
98    /// use bytes::Bytes;
99    ///
100    /// # #[tokio::main]
101    /// async fn main() {
102    /// let (tx, rx) = tokio::sync::oneshot::channel::<HeaderMap>();
103    ///
104    /// let body = Full::<Bytes>::from("Hello, World!")
105    ///     // add trailers via a future
106    ///     .with_trailers(async move {
107    ///         match rx.await {
108    ///             Ok(trailers) => Some(Ok(trailers)),
109    ///             Err(_err) => None,
110    ///         }
111    ///     });
112    ///
113    /// // compute the trailers in the background
114    /// tokio::spawn(async move {
115    ///     let _ = tx.send(compute_trailers().await);
116    /// });
117    ///
118    /// async fn compute_trailers() -> HeaderMap {
119    ///     // ...
120    ///     # unimplemented!()
121    /// }
122    /// # }
123    /// ```
124    fn with_trailers<F>(self, trailers: F) -> combinators::WithTrailers<Self, F>
125    where
126        Self: Sized,
127        F: std::future::Future<Output = Option<Result<http::HeaderMap, Self::Error>>>,
128    {
129        combinators::WithTrailers::new(self, trailers)
130    }
131
132    /// Turn this body into [`BodyDataStream`].
133    fn into_data_stream(self) -> BodyDataStream<Self>
134    where
135        Self: Sized,
136    {
137        BodyDataStream::new(self)
138    }
139}
140
141impl<T: ?Sized> BodyExt for T where T: http_body::Body {}