//! [`MessageBody`] trait and foreign implementations. use std::{ convert::Infallible, mem, pin::Pin, task::{Context, Poll}, }; use bytes::{Bytes, BytesMut}; use futures_core::ready; use pin_project_lite::pin_project; use super::BodySize; /// An interface for response bodies. pub trait MessageBody { type Error; /// Body size hint. fn size(&self) -> BodySize; /// Attempt to pull out the next chunk of body bytes. fn poll_next( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>>; } impl MessageBody for () { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(0) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { Poll::Ready(None) } } impl MessageBody for Box where B: MessageBody + Unpin, { type Error = B::Error; fn size(&self) -> BodySize { self.as_ref().size() } fn poll_next( self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>> { Pin::new(self.get_mut().as_mut()).poll_next(cx) } } impl MessageBody for Pin> where B: MessageBody, { type Error = B::Error; fn size(&self) -> BodySize { self.as_ref().size() } fn poll_next( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>> { self.as_mut().poll_next(cx) } } impl MessageBody for Bytes { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(self.len() as u64) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { if self.is_empty() { Poll::Ready(None) } else { Poll::Ready(Some(Ok(mem::take(self.get_mut())))) } } } impl MessageBody for BytesMut { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(self.len() as u64) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { if self.is_empty() { Poll::Ready(None) } else { Poll::Ready(Some(Ok(mem::take(self.get_mut()).freeze()))) } } } impl MessageBody for &'static str { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(self.len() as u64) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { if self.is_empty() { Poll::Ready(None) } else { Poll::Ready(Some(Ok(Bytes::from_static( mem::take(self.get_mut()).as_ref(), )))) } } } impl MessageBody for Vec { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(self.len() as u64) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { if self.is_empty() { Poll::Ready(None) } else { Poll::Ready(Some(Ok(Bytes::from(mem::take(self.get_mut()))))) } } } impl MessageBody for String { type Error = Infallible; fn size(&self) -> BodySize { BodySize::Sized(self.len() as u64) } fn poll_next( self: Pin<&mut Self>, _: &mut Context<'_>, ) -> Poll>> { if self.is_empty() { Poll::Ready(None) } else { Poll::Ready(Some(Ok(Bytes::from( mem::take(self.get_mut()).into_bytes(), )))) } } } pin_project! { pub(crate) struct MessageBodyMapErr { #[pin] body: B, mapper: Option, } } impl MessageBodyMapErr where B: MessageBody, F: FnOnce(B::Error) -> E, { pub(crate) fn new(body: B, mapper: F) -> Self { Self { body, mapper: Some(mapper), } } } impl MessageBody for MessageBodyMapErr where B: MessageBody, F: FnOnce(B::Error) -> E, { type Error = E; fn size(&self) -> BodySize { self.body.size() } fn poll_next( mut self: Pin<&mut Self>, cx: &mut Context<'_>, ) -> Poll>> { let this = self.as_mut().project(); match ready!(this.body.poll_next(cx)) { Some(Err(err)) => { let f = self.as_mut().project().mapper.take().unwrap(); let mapped_err = (f)(err); Poll::Ready(Some(Err(mapped_err))) } Some(Ok(val)) => Poll::Ready(Some(Ok(val))), None => Poll::Ready(None), } } }