Skip to content

Commit 23212f1

Browse files
authored
feat(util): add BodyDataStream (#117)
1 parent fe8aa7e commit 23212f1

File tree

5 files changed

+49
-6
lines changed

5 files changed

+49
-6
lines changed

http-body-util/Cargo.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,10 @@ rust-version = "1.49"
2828

2929
[dependencies]
3030
bytes = "1"
31-
futures-core = "0.3"
31+
futures-util = { version = "0.3", default-features = false }
3232
http = "1"
3333
http-body = { version = "1", path = "../http-body" }
3434
pin-project-lite = "0.2"
3535

3636
[dev-dependencies]
3737
tokio = { version = "1", features = ["macros", "rt", "sync", "rt-multi-thread"] }
38-
futures-util = { version = "0.3.14", default-features = false }

http-body-util/src/combinators/collect.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ impl<T: Body + ?Sized> Future for Collect<T> {
2929
let mut me = self.project();
3030

3131
loop {
32-
let frame = futures_core::ready!(me.body.as_mut().poll_frame(cx));
32+
let frame = futures_util::ready!(me.body.as_mut().poll_frame(cx));
3333

3434
let frame = if let Some(frame) = frame {
3535
frame?

http-body-util/src/combinators/with_trailers.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::{
44
task::{Context, Poll},
55
};
66

7-
use futures_core::ready;
7+
use futures_util::ready;
88
use http::HeaderMap;
99
use http_body::{Body, Frame};
1010
use pin_project_lite::pin_project;

http-body-util/src/lib.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub use self::either::Either;
2424
pub use self::empty::Empty;
2525
pub use self::full::Full;
2626
pub use self::limited::{LengthLimitError, Limited};
27-
pub use self::stream::{BodyStream, StreamBody};
27+
pub use self::stream::{BodyDataStream, BodyStream, StreamBody};
2828

2929
/// An extension trait for [`http_body::Body`] adding various combinators and adapters
3030
pub trait BodyExt: http_body::Body {
@@ -128,6 +128,14 @@ pub trait BodyExt: http_body::Body {
128128
{
129129
combinators::WithTrailers::new(self, trailers)
130130
}
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+
}
131139
}
132140

133141
impl<T: ?Sized> BodyExt for T where T: http_body::Body {}

http-body-util/src/stream.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use bytes::Buf;
2-
use futures_core::Stream;
2+
use futures_util::{ready, stream::Stream};
33
use http_body::{Body, Frame};
44
use pin_project_lite::pin_project;
55
use std::{
@@ -101,6 +101,42 @@ where
101101
}
102102
}
103103

104+
pin_project! {
105+
/// A data stream created from a [`Body`].
106+
#[derive(Clone, Copy, Debug)]
107+
pub struct BodyDataStream<B> {
108+
#[pin]
109+
body: B,
110+
}
111+
}
112+
113+
impl<B> BodyDataStream<B> {
114+
/// Create a new `BodyDataStream`
115+
pub fn new(body: B) -> Self {
116+
Self { body }
117+
}
118+
}
119+
120+
impl<B> Stream for BodyDataStream<B>
121+
where
122+
B: Body,
123+
{
124+
type Item = Result<B::Data, B::Error>;
125+
126+
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
127+
loop {
128+
return match ready!(self.as_mut().project().body.poll_frame(cx)) {
129+
Some(Ok(frame)) => match frame.into_data() {
130+
Ok(bytes) => Poll::Ready(Some(Ok(bytes))),
131+
Err(_) => continue,
132+
},
133+
Some(Err(err)) => Poll::Ready(Some(Err(err))),
134+
None => Poll::Ready(None),
135+
};
136+
}
137+
}
138+
}
139+
104140
#[cfg(test)]
105141
mod tests {
106142
use crate::{BodyExt, BodyStream, StreamBody};

0 commit comments

Comments
 (0)