diff --git a/http-body-util/src/lib.rs b/http-body-util/src/lib.rs index 28709fb..95bb04f 100644 --- a/http-body-util/src/lib.rs +++ b/http-body-util/src/lib.rs @@ -13,6 +13,7 @@ mod either; mod empty; mod full; mod limited; +mod response_ext; mod stream; #[cfg(feature = "channel")] @@ -22,16 +23,16 @@ mod util; use self::combinators::{BoxBody, MapErr, MapFrame, UnsyncBoxBody}; +#[cfg(feature = "channel")] +pub use self::channel::Channel; pub use self::collected::Collected; pub use self::either::Either; pub use self::empty::Empty; pub use self::full::Full; pub use self::limited::{LengthLimitError, Limited}; +pub use self::response_ext::ResponseExt; pub use self::stream::{BodyDataStream, BodyStream, StreamBody}; -#[cfg(feature = "channel")] -pub use self::channel::Channel; - /// An extension trait for [`http_body::Body`] adding various combinators and adapters pub trait BodyExt: http_body::Body { /// Returns a future that resolves to the next [`Frame`], if any. diff --git a/http-body-util/src/response_ext.rs b/http-body-util/src/response_ext.rs new file mode 100644 index 0000000..015f8f9 --- /dev/null +++ b/http-body-util/src/response_ext.rs @@ -0,0 +1,116 @@ +use crate::combinators::{BoxBody, UnsyncBoxBody}; + +/// An extension trait for [`http::Request`] adding various combinators and adapters +pub trait ResponseExt { + /// Returns a new `http::Response` with the body boxed. + /// + /// This is useful when you have need to return a Response where the body type is not known at + /// compile time. + /// + /// # Example + /// + /// ``` + /// use bytes::Bytes; + /// use http::Response; + /// use http_body_util::{Empty, ResponseExt}; + /// + /// # let some_condition = true; + /// let response = if some_condition { + /// greeting().box_body() + /// } else { + /// empty().box_body() + /// }; + /// + /// fn greeting() -> Response { + /// Response::new("Hello, World!".to_string()) + /// } + /// + /// fn empty() -> Response> { + /// Response::new(Empty::new()) + /// } + /// ``` + fn box_body(self) -> http::Response> + where + B: http_body::Body + Send + Sync + 'static; + + /// Returns a new `http::Response` with the body boxed and !Sync. + /// + /// This is useful when you have need to return a Response where the body type is not known at + /// compile time and the body is not Sync. + /// + /// # Example + /// + /// ``` + /// use bytes::Bytes; + /// use http::Response; + /// use http_body_util::{Empty, ResponseExt}; + /// + /// # let some_condition = true; + /// let response = if some_condition { + /// greeting().box_body_unsync() + /// } else { + /// empty().box_body_unsync() + /// }; + /// + /// fn greeting() -> Response { + /// Response::new("Hello, World!".to_string()) + /// } + /// + /// fn empty() -> Response> { + /// Response::new(Empty::new()) + /// } + /// ``` + fn box_body_unsync(self) -> http::Response> + where + B: http_body::Body + Send + 'static; +} + +impl ResponseExt for http::Response { + fn box_body(self) -> http::Response> + where + B: http_body::Body + Send + Sync + 'static, + { + self.map(crate::BodyExt::boxed) + } + + fn box_body_unsync(self) -> http::Response> + where + B: http_body::Body + Send + 'static, + { + self.map(crate::BodyExt::boxed_unsync) + } +} + +#[cfg(test)] +mod tests { + use bytes::Bytes; + use http::{Response, StatusCode, Uri}; + + use super::*; + use crate::{Empty, Full}; + + #[test] + fn box_body() { + let uri: Uri = "http://example.com".parse().unwrap(); + let _response = match uri.path() { + "/greeting" => greeting().box_body(), + "/empty" => empty().box_body(), + _ => not_found().box_body(), + }; + } + + fn greeting() -> Response { + Response::new("Hello, World!".to_string()) + } + + fn empty() -> Response> { + Response::new(Empty::new()) + } + + fn not_found() -> Response> { + Response::builder() + .status(StatusCode::NOT_FOUND) + .body("Not Found".into()) + .unwrap() + } +}