From d36ca3a13387fca45ae72903bd297f730c97d1dc Mon Sep 17 00:00:00 2001 From: Rob Ede Date: Tue, 23 Nov 2021 18:05:44 +0000 Subject: [PATCH] introduce either body --- actix-http/CHANGES.md | 8 +++ actix-http/src/body/either.rs | 83 +++++++++++++++++++++++++++++ actix-http/src/body/message_body.rs | 15 ++++++ actix-http/src/body/mod.rs | 5 +- 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 actix-http/src/body/either.rs diff --git a/actix-http/CHANGES.md b/actix-http/CHANGES.md index d9164c54e..52626d7fc 100644 --- a/actix-http/CHANGES.md +++ b/actix-http/CHANGES.md @@ -5,10 +5,18 @@ * Add timeout for canceling HTTP/2 server side connection handshake. Default to 5 seconds. [#2483] * HTTP/2 handshake timeout can be configured with `ServiceConfig::client_timeout`. [#2483] * Rename `body::BoxBody::{from_body => new}`. [#????] +* `body::EitherBody` enum. [#????] + +### Changed +* Rename `body::BoxBody::{from_body => new}`. [#????] + +### Removed +* Remove unnecessary `MessageBody` bound on types passed to `body::AnyBody::new`. [#????] [#2483]: https://github.com/actix/actix-web/pull/2483 [#????]: https://github.com/actix/actix-web/pull/???? + ## 3.0.0-beta.14 - 2021-11-30 ### Changed * Guarantee ordering of `header::GetAll` iterator to be same as insertion order. [#2467] diff --git a/actix-http/src/body/either.rs b/actix-http/src/body/either.rs new file mode 100644 index 000000000..e58d30237 --- /dev/null +++ b/actix-http/src/body/either.rs @@ -0,0 +1,83 @@ +use std::{ + error::Error as StdError, + pin::Pin, + task::{Context, Poll}, +}; + +use bytes::Bytes; +use pin_project_lite::pin_project; + +use super::{BodySize, BoxBody, MessageBody}; +use crate::Error; + +pin_project! { + #[project = EitherBodyProj] + #[derive(Debug, Clone)] + pub enum EitherBody { + /// A body of type `L`. + Left { #[pin] body: L }, + + /// A body of type `R`. + Right { #[pin] body: R }, + } +} + +impl EitherBody { + /// Creates new `EitherBody` using left variant and boxed right variant. + pub fn new(body: L) -> Self { + Self::Left { body } + } +} + +impl EitherBody { + /// Creates new `EitherBody` using left variant. + pub fn left(body: L) -> Self { + Self::Left { body } + } + + /// Creates new `EitherBody` using right variant. + pub fn right(body: R) -> Self { + Self::Right { body } + } +} + +impl MessageBody for EitherBody +where + L: MessageBody + 'static, + L::Error: Into>, + R: MessageBody + 'static, + R::Error: Into>, +{ + type Error = Error; + + fn size(&self) -> BodySize { + match self { + EitherBody::Left { body } => body.size(), + EitherBody::Right { body } => body.size(), + } + } + + fn poll_next( + self: Pin<&mut Self>, + cx: &mut Context<'_>, + ) -> Poll>> { + match self.project() { + EitherBodyProj::Left { body } => body + .poll_next(cx) + .map_err(|err| Error::new_body().with_cause(err)), + EitherBodyProj::Right { body } => body + .poll_next(cx) + .map_err(|err| Error::new_body().with_cause(err)), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn either_body_works() { + EitherBody::left(()); + } +} diff --git a/actix-http/src/body/message_body.rs b/actix-http/src/body/message_body.rs index 62a7e9b1c..932afd2e5 100644 --- a/actix-http/src/body/message_body.rs +++ b/actix-http/src/body/message_body.rs @@ -27,6 +27,21 @@ pub trait MessageBody { ) -> Poll>>; } +impl MessageBody for Infallible { + type Error = Infallible; + + fn size(&self) -> BodySize { + match *self {} + } + + fn poll_next( + self: Pin<&mut Self>, + _: &mut Context<'_>, + ) -> Poll>> { + match *self {} + } +} + impl MessageBody for () { type Error = Infallible; diff --git a/actix-http/src/body/mod.rs b/actix-http/src/body/mod.rs index c4caad5e0..83d20b1d0 100644 --- a/actix-http/src/body/mod.rs +++ b/actix-http/src/body/mod.rs @@ -11,14 +11,17 @@ use futures_core::ready; mod body; mod body_stream; mod boxed; +mod either; mod message_body; mod size; mod sized_stream; +pub use self::body::AnyBody; #[allow(deprecated)] -pub use self::body::{AnyBody, Body, BoxBody}; +pub use self::body::Body; pub use self::body_stream::BodyStream; pub use self::boxed::BoxBody; +pub use self::either::EitherBody; pub use self::message_body::MessageBody; pub(crate) use self::message_body::MessageBodyMapErr; pub use self::size::BodySize;