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