Skip to content

Commit 03d3328

Browse files
committed
Add axum_core::body::Body (#1584)
1 parent 3169557 commit 03d3328

1 file changed

Lines changed: 92 additions & 2 deletions

File tree

axum-core/src/body.rs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
use crate::{BoxError, Error};
44
use bytes::Bytes;
55
use bytes::{Buf, BufMut};
6-
use http_body::Body;
6+
use futures_util::stream::Stream;
7+
use http::HeaderMap;
8+
use http_body::Body as _;
9+
use std::pin::Pin;
10+
use std::task::{Context, Poll};
711

812
/// A boxed [`Body`] trait object.
913
///
@@ -55,7 +59,7 @@ where
5559
// THE SOFTWARE.
5660
pub(crate) async fn to_bytes<T>(body: T) -> Result<Bytes, T::Error>
5761
where
58-
T: Body,
62+
T: http_body::Body,
5963
{
6064
futures_util::pin_mut!(body);
6165

@@ -85,6 +89,92 @@ where
8589
Ok(vec.into())
8690
}
8791

92+
/// The body type used in axum requests and responses.
93+
#[derive(Debug)]
94+
pub struct Body(BoxBody);
95+
96+
impl Body {
97+
/// Create a new `Body` that wraps another [`http_body::Body`].
98+
pub fn new<B>(body: B) -> Self
99+
where
100+
B: http_body::Body<Data = Bytes> + Send + 'static,
101+
B::Error: Into<BoxError>,
102+
{
103+
try_downcast(body).unwrap_or_else(|body| Self(boxed(body)))
104+
}
105+
106+
/// Create an empty body.
107+
pub fn empty() -> Self {
108+
Self::new(http_body::Empty::new())
109+
}
110+
}
111+
112+
impl Default for Body {
113+
fn default() -> Self {
114+
Self::empty()
115+
}
116+
}
117+
118+
macro_rules! body_from_impl {
119+
($ty:ty) => {
120+
impl From<$ty> for Body {
121+
fn from(buf: $ty) -> Self {
122+
Self::new(http_body::Full::from(buf))
123+
}
124+
}
125+
};
126+
}
127+
128+
body_from_impl!(&'static [u8]);
129+
body_from_impl!(std::borrow::Cow<'static, [u8]>);
130+
body_from_impl!(Vec<u8>);
131+
132+
body_from_impl!(&'static str);
133+
body_from_impl!(std::borrow::Cow<'static, str>);
134+
body_from_impl!(String);
135+
136+
body_from_impl!(Bytes);
137+
138+
impl http_body::Body for Body {
139+
type Data = Bytes;
140+
type Error = Error;
141+
142+
#[inline]
143+
fn poll_data(
144+
mut self: Pin<&mut Self>,
145+
cx: &mut Context<'_>,
146+
) -> std::task::Poll<Option<Result<Self::Data, Self::Error>>> {
147+
Pin::new(&mut self.0).poll_data(cx)
148+
}
149+
150+
#[inline]
151+
fn poll_trailers(
152+
mut self: Pin<&mut Self>,
153+
cx: &mut Context<'_>,
154+
) -> std::task::Poll<Result<Option<HeaderMap>, Self::Error>> {
155+
Pin::new(&mut self.0).poll_trailers(cx)
156+
}
157+
158+
#[inline]
159+
fn size_hint(&self) -> http_body::SizeHint {
160+
self.0.size_hint()
161+
}
162+
163+
#[inline]
164+
fn is_end_stream(&self) -> bool {
165+
self.0.is_end_stream()
166+
}
167+
}
168+
169+
impl Stream for Body {
170+
type Item = Result<Bytes, Error>;
171+
172+
#[inline]
173+
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
174+
self.poll_data(cx)
175+
}
176+
}
177+
88178
#[test]
89179
fn test_try_downcast() {
90180
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));

0 commit comments

Comments
 (0)