use pin-project-lite on anybody

This commit is contained in:
Rob Ede 2021-11-30 15:19:21 +00:00
parent 81d6fb4d65
commit aec0e46909
No known key found for this signature in database
GPG Key ID: 97C636207D3EF933
4 changed files with 82 additions and 48 deletions

View File

@ -8,7 +8,7 @@ use std::{
use bytes::{Bytes, BytesMut}; use bytes::{Bytes, BytesMut};
use futures_core::Stream; use futures_core::Stream;
use pin_project::pin_project; use pin_project_lite::pin_project;
use super::{BodySize, BodyStream, BoxBody, MessageBody, SizedStream}; use super::{BodySize, BodyStream, BoxBody, MessageBody, SizedStream};
use crate::error::Error; use crate::error::Error;
@ -17,18 +17,20 @@ use crate::error::Error;
#[deprecated(since = "4.0.0", note = "Renamed to `AnyBody`.")] #[deprecated(since = "4.0.0", note = "Renamed to `AnyBody`.")]
pub type Body = AnyBody; pub type Body = AnyBody;
/// Represents various types of HTTP message body. pin_project! {
#[pin_project(project = AnyBodyProj)] /// Represents various types of HTTP message body.
#[derive(Clone)] #[derive(Clone)]
pub enum AnyBody<B = BoxBody> { #[project = AnyBodyProj]
/// Empty response. `Content-Length` header is not set. pub enum AnyBody<B = BoxBody> {
None, /// Empty response. `Content-Length` header is not set.
None,
/// Complete, in-memory response body. /// Complete, in-memory response body.
Bytes(Bytes), Bytes { body: Bytes },
/// Generic / Other message body. /// Generic / Other message body.
Body(#[pin] B), Body { #[pin] body: B },
}
} }
impl AnyBody { impl AnyBody {
@ -39,7 +41,7 @@ impl AnyBody {
/// Constructs a new, 0-length body. /// Constructs a new, 0-length body.
pub fn empty() -> Self { pub fn empty() -> Self {
Self::Bytes(Bytes::new()) Self::Bytes { body: Bytes::new() }
} }
/// Create boxed body from generic message body. /// Create boxed body from generic message body.
@ -48,27 +50,33 @@ impl AnyBody {
B: MessageBody + 'static, B: MessageBody + 'static,
B::Error: Into<Box<dyn StdError + 'static>>, B::Error: Into<Box<dyn StdError + 'static>>,
{ {
Self::Body(BoxBody::new(body)) Self::Body {
body: BoxBody::new(body),
}
} }
/// Constructs new `AnyBody` instance from a slice of bytes by copying it. /// Constructs new `AnyBody` instance from a slice of bytes by copying it.
/// ///
/// If your bytes container is owned, it may be cheaper to use a `From` impl. /// If your bytes container is owned, it may be cheaper to use a `From` impl.
pub fn copy_from_slice(s: &[u8]) -> Self { pub fn copy_from_slice(s: &[u8]) -> Self {
Self::Bytes(Bytes::copy_from_slice(s)) Self::Bytes {
body: Bytes::copy_from_slice(s),
}
} }
#[doc(hidden)] #[doc(hidden)]
#[deprecated(since = "4.0.0", note = "Renamed to `copy_from_slice`.")] #[deprecated(since = "4.0.0", note = "Renamed to `copy_from_slice`.")]
pub fn from_slice(s: &[u8]) -> Self { pub fn from_slice(s: &[u8]) -> Self {
Self::Bytes(Bytes::copy_from_slice(s)) Self::Bytes {
body: Bytes::copy_from_slice(s),
}
} }
} }
impl<B> AnyBody<B> { impl<B> AnyBody<B> {
/// Create body from generic message body. /// Create body from generic message body.
pub fn new(body: B) -> Self { pub fn new(body: B) -> Self {
Self::Body(body) Self::Body { body }
} }
} }
@ -80,8 +88,8 @@ where
pub fn into_boxed(self) -> AnyBody { pub fn into_boxed(self) -> AnyBody {
match self { match self {
Self::None => AnyBody::None, Self::None => AnyBody::None,
Self::Bytes(bytes) => AnyBody::Bytes(bytes), Self::Bytes { body: bytes } => AnyBody::Bytes { body: bytes },
Self::Body(body) => AnyBody::new_boxed(body), Self::Body { body } => AnyBody::new_boxed(body),
} }
} }
} }
@ -96,8 +104,8 @@ where
fn size(&self) -> BodySize { fn size(&self) -> BodySize {
match self { match self {
AnyBody::None => BodySize::None, AnyBody::None => BodySize::None,
AnyBody::Bytes(ref bin) => BodySize::Sized(bin.len() as u64), AnyBody::Bytes { ref body } => BodySize::Sized(body.len() as u64),
AnyBody::Body(ref body) => body.size(), AnyBody::Body { ref body } => body.size(),
} }
} }
@ -107,16 +115,16 @@ where
) -> Poll<Option<Result<Bytes, Self::Error>>> { ) -> Poll<Option<Result<Bytes, Self::Error>>> {
match self.project() { match self.project() {
AnyBodyProj::None => Poll::Ready(None), AnyBodyProj::None => Poll::Ready(None),
AnyBodyProj::Bytes(bin) => { AnyBodyProj::Bytes { body } => {
let len = bin.len(); let len = body.len();
if len == 0 { if len == 0 {
Poll::Ready(None) Poll::Ready(None)
} else { } else {
Poll::Ready(Some(Ok(mem::take(bin)))) Poll::Ready(Some(Ok(mem::take(body))))
} }
} }
AnyBodyProj::Body(body) => body AnyBodyProj::Body { body } => body
.poll_next(cx) .poll_next(cx)
.map_err(|err| Error::new_body().with_cause(err)), .map_err(|err| Error::new_body().with_cause(err)),
} }
@ -125,13 +133,13 @@ where
impl PartialEq for AnyBody { impl PartialEq for AnyBody {
fn eq(&self, other: &AnyBody) -> bool { fn eq(&self, other: &AnyBody) -> bool {
match *self { match self {
AnyBody::None => matches!(*other, AnyBody::None), AnyBody::None => matches!(*other, AnyBody::None),
AnyBody::Bytes(ref b) => match *other { AnyBody::Bytes { body } => match other {
AnyBody::Bytes(ref b2) => b == b2, AnyBody::Bytes { body: b2 } => body == b2,
_ => false, _ => false,
}, },
AnyBody::Body(_) => false, AnyBody::Body { .. } => false,
} }
} }
} }
@ -140,39 +148,49 @@ impl<S: fmt::Debug> fmt::Debug for AnyBody<S> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self { match *self {
AnyBody::None => write!(f, "AnyBody::None"), AnyBody::None => write!(f, "AnyBody::None"),
AnyBody::Bytes(ref bytes) => write!(f, "AnyBody::Bytes({:?})", bytes), AnyBody::Bytes { ref body } => write!(f, "AnyBody::Bytes({:?})", body),
AnyBody::Body(ref stream) => write!(f, "AnyBody::Message({:?})", stream), AnyBody::Body { ref body } => write!(f, "AnyBody::Message({:?})", body),
} }
} }
} }
impl<B> From<&'static str> for AnyBody<B> { impl<B> From<&'static str> for AnyBody<B> {
fn from(string: &'static str) -> Self { fn from(string: &'static str) -> Self {
Self::Bytes(Bytes::from_static(string.as_ref())) Self::Bytes {
body: Bytes::from_static(string.as_ref()),
}
} }
} }
impl<B> From<&'static [u8]> for AnyBody<B> { impl<B> From<&'static [u8]> for AnyBody<B> {
fn from(bytes: &'static [u8]) -> Self { fn from(bytes: &'static [u8]) -> Self {
Self::Bytes(Bytes::from_static(bytes)) Self::Bytes {
body: Bytes::from_static(bytes),
}
} }
} }
impl<B> From<Vec<u8>> for AnyBody<B> { impl<B> From<Vec<u8>> for AnyBody<B> {
fn from(vec: Vec<u8>) -> Self { fn from(vec: Vec<u8>) -> Self {
Self::Bytes(Bytes::from(vec)) Self::Bytes {
body: Bytes::from(vec),
}
} }
} }
impl<B> From<String> for AnyBody<B> { impl<B> From<String> for AnyBody<B> {
fn from(string: String) -> Self { fn from(string: String) -> Self {
Self::Bytes(Bytes::from(string)) Self::Bytes {
body: Bytes::from(string),
}
} }
} }
impl<B> From<&'_ String> for AnyBody<B> { impl<B> From<&'_ String> for AnyBody<B> {
fn from(string: &String) -> Self { fn from(string: &String) -> Self {
Self::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&string))) Self::Bytes {
body: Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(&string)),
}
} }
} }
@ -180,22 +198,24 @@ impl<B> From<Cow<'_, str>> for AnyBody<B> {
fn from(string: Cow<'_, str>) -> Self { fn from(string: Cow<'_, str>) -> Self {
match string { match string {
Cow::Owned(s) => Self::from(s), Cow::Owned(s) => Self::from(s),
Cow::Borrowed(s) => { Cow::Borrowed(s) => Self::Bytes {
Self::Bytes(Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(s))) body: Bytes::copy_from_slice(AsRef::<[u8]>::as_ref(s)),
} },
} }
} }
} }
impl<B> From<Bytes> for AnyBody<B> { impl<B> From<Bytes> for AnyBody<B> {
fn from(bytes: Bytes) -> Self { fn from(bytes: Bytes) -> Self {
Self::Bytes(bytes) Self::Bytes { body: bytes }
} }
} }
impl<B> From<BytesMut> for AnyBody<B> { impl<B> From<BytesMut> for AnyBody<B> {
fn from(bytes: BytesMut) -> Self { fn from(bytes: BytesMut) -> Self {
Self::Bytes(bytes.freeze()) Self::Bytes {
body: bytes.freeze(),
}
} }
} }

View File

@ -37,7 +37,7 @@ mod tests {
impl TestAnyBody { impl TestAnyBody {
pub(crate) fn get_ref(&self) -> &[u8] { pub(crate) fn get_ref(&self) -> &[u8] {
match *self { match *self {
AnyBody::Bytes(ref bin) => bin, AnyBody::Bytes { ref body } => body,
_ => panic!(), _ => panic!(),
} }
} }
@ -168,10 +168,18 @@ mod tests {
#[actix_rt::test] #[actix_rt::test]
async fn test_body_eq() { async fn test_body_eq() {
assert!( assert!(
AnyBody::Bytes(Bytes::from_static(b"1")) AnyBody::Bytes {
== AnyBody::Bytes(Bytes::from_static(b"1")) body: Bytes::from_static(b"1")
} == AnyBody::Bytes {
body: Bytes::from_static(b"1")
}
);
assert!(
AnyBody::Bytes {
body: Bytes::from_static(b"1")
} != AnyBody::None
); );
assert!(AnyBody::Bytes(Bytes::from_static(b"1")) != AnyBody::None);
} }
#[actix_rt::test] #[actix_rt::test]

View File

@ -95,7 +95,7 @@ where
}; };
let body_opt = match body { let body_opt = match body {
AnyBody::Bytes(ref b) => Some(b.clone()), AnyBody::Bytes { ref body } => Some(body.clone()),
_ => None, _ => None,
}; };
@ -192,7 +192,9 @@ where
let body_new = if is_redirect { let body_new = if is_redirect {
// try to reuse body // try to reuse body
match body { match body {
Some(ref bytes) => AnyBody::Bytes(bytes.clone()), Some(ref bytes) => AnyBody::Bytes {
body: bytes.clone(),
},
// TODO: should this be AnyBody::Empty or AnyBody::None. // TODO: should this be AnyBody::Empty or AnyBody::None.
_ => AnyBody::empty(), _ => AnyBody::empty(),
} }

View File

@ -236,7 +236,9 @@ impl RequestSender {
response_decompress, response_decompress,
timeout, timeout,
config, config,
AnyBody::Bytes(Bytes::from(body)), AnyBody::Bytes {
body: Bytes::from(body),
},
) )
} }
@ -265,7 +267,9 @@ impl RequestSender {
response_decompress, response_decompress,
timeout, timeout,
config, config,
AnyBody::Bytes(Bytes::from(body)), AnyBody::Bytes {
body: Bytes::from(body),
},
) )
} }