Skip to main content

stream_body/
lib.rs

1//! An [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) implementation with efficient streaming support for the Rust HTTP library [hyper](https://hyper.rs/).
2//!
3//! # Motivation
4//!
5//! The existing [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) type in [hyper](https://hyper.rs/) uses [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html)
6//! as streaming chunk. Hence, a lot of buffer allocation and de-allocation happen during the real-time large data streaming because of the [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) type.
7//! Therefore, `StreamBody` comes to tackle this kind of situation. The `StreamBody` implements [HttpBody](https://docs.rs/hyper/0.13.4/hyper/body/trait.HttpBody.html) and uses `&[u8]`
8//! slice as the streaming chunk, so it is possible to use the same buffer without allocating a new one; hence it overcomes any allocation/de-allocation overhead.
9//!
10//! Also, the [channel()](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html#method.channel) method in hyper [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html) returns
11//! a pair of a [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) and a [Body](https://docs.rs/hyper/0.13.4/hyper/body/struct.Body.html).
12//! Here, the [Sender](https://docs.rs/hyper/0.13.4/hyper/body/struct.Sender.html) accepts [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html) as a data chunk which again
13//! creates allocation/de-allocation overhead.
14//! To solve this, `StreamBody` has a method named `StreamBody::channel()` which returns a pair of an [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) and the `StreamBody`
15//! itself. As the [AsyncWrite](https://docs.rs/tokio/0.2.16/tokio/io/trait.AsyncWrite.html) accepts `&[u8]` instead of [Bytes](https://docs.rs/bytes/0.5.4/bytes/struct.Bytes.html), there will
16//! be no allocation/de-allocation overhead.
17//!
18//! # Examples
19//!
20//! ```
21//! use hyper::service::{make_service_fn, service_fn};
22//! use hyper::{Body, Request, Response, Server};
23//! use std::{convert::Infallible, net::SocketAddr};
24//! use stream_body::StreamBody;
25//! use tokio::fs::File;
26//! use tokio::io::{AsyncReadExt, AsyncWriteExt};
27//!
28//! async fn handle(_: Request<Body>) -> Result<Response<StreamBody>, Infallible> {
29//!     let (mut writer, body) = StreamBody::channel();
30//!
31//!     tokio::spawn(async move {
32//!         let mut f = File::open("large-file").await.unwrap();
33//!
34//!         // Reuse this buffer
35//!         let mut buf = [0_u8; 1024 * 16];
36//!         loop {
37//!             let read_count = f.read(&mut buf).await.unwrap();
38//!             if read_count == 0 {
39//!                 break;
40//!             }
41//!             writer.write_all(&buf[..read_count]).await.unwrap();
42//!         }
43//!     });
44//!
45//!     Ok(Response::builder().body(body).unwrap())
46//! }
47//!
48//! #[tokio::main]
49//! async fn main() {
50//!     let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
51//!
52//!     let make_svc = make_service_fn(|_conn| async { Ok::<_, Infallible>(service_fn(handle)) });
53//!
54//!    let server = Server::bind(&addr).serve(make_svc);
55//!
56//!    if let Err(e) = server.await {
57//!        eprintln!("server error: {}", e);
58//!     }
59//! }
60//! ```
61
62pub use self::body::StreamBody;
63pub use self::data::StreamData;
64
65mod body;
66mod data;
67mod state;