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 | |
10 | mod collected; |
11 | pub mod combinators; |
12 | mod either; |
13 | mod empty; |
14 | mod full; |
15 | mod limited; |
16 | mod stream; |
17 | |
18 | #[cfg (feature = "channel" )] |
19 | pub mod channel; |
20 | |
21 | mod util; |
22 | |
23 | use self::combinators::{BoxBody, MapErr, MapFrame, UnsyncBoxBody}; |
24 | |
25 | pub use self::collected::Collected; |
26 | pub use self::either::Either; |
27 | pub use self::empty::Empty; |
28 | pub use self::full::Full; |
29 | pub use self::limited::{LengthLimitError, Limited}; |
30 | pub use self::stream::{BodyDataStream, BodyStream, StreamBody}; |
31 | |
32 | #[cfg (feature = "channel" )] |
33 | pub use self::channel::Channel; |
34 | |
35 | /// An extension trait for [`http_body::Body`] adding various combinators and adapters |
36 | pub 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 | |
147 | impl<T: ?Sized> BodyExt for T where T: http_body::Body {} |
148 | |