use crate::{Body, SizeHint}; use bytes::{Buf, Bytes}; use http::HeaderMap; use pin_project_lite::pin_project; use std::borrow::Cow; use std::convert::{Infallible, TryFrom}; use std::pin::Pin; use std::task::{Context, Poll}; pin_project! { /// A body that consists of a single chunk. #[derive(Clone, Copy, Debug)] pub struct Full { data: Option, } } impl Full where D: Buf, { /// Create a new `Full`. pub fn new(data: D) -> Self { let data = if data.has_remaining() { Some(data) } else { None }; Full { data } } } impl Body for Full where D: Buf, { type Data = D; type Error = Infallible; fn poll_data( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll>> { Poll::Ready(self.data.take().map(Ok)) } fn poll_trailers( self: Pin<&mut Self>, _cx: &mut Context<'_>, ) -> Poll, Self::Error>> { Poll::Ready(Ok(None)) } fn is_end_stream(&self) -> bool { self.data.is_none() } fn size_hint(&self) -> SizeHint { self.data .as_ref() .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap())) .unwrap_or_else(|| SizeHint::with_exact(0)) } } impl Default for Full where D: Buf, { /// Create an empty `Full`. fn default() -> Self { Full { data: None } } } impl From for Full where D: Buf + From, { fn from(bytes: Bytes) -> Self { Full::new(D::from(bytes)) } } impl From> for Full where D: Buf + From>, { fn from(vec: Vec) -> Self { Full::new(D::from(vec)) } } impl From<&'static [u8]> for Full where D: Buf + From<&'static [u8]>, { fn from(slice: &'static [u8]) -> Self { Full::new(D::from(slice)) } } impl From> for Full where D: Buf + From<&'static B> + From, B: ToOwned + ?Sized, { fn from(cow: Cow<'static, B>) -> Self { match cow { Cow::Borrowed(b) => Full::new(D::from(b)), Cow::Owned(o) => Full::new(D::from(o)), } } } impl From for Full where D: Buf + From, { fn from(s: String) -> Self { Full::new(D::from(s)) } } impl From<&'static str> for Full where D: Buf + From<&'static str>, { fn from(slice: &'static str) -> Self { Full::new(D::from(slice)) } } #[cfg(test)] mod tests { use super::*; #[tokio::test] async fn full_returns_some() { let mut full = Full::new(&b"hello"[..]); assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64)); assert_eq!(full.data().await, Some(Ok(&b"hello"[..]))); assert!(full.data().await.is_none()); } #[tokio::test] async fn empty_full_returns_none() { assert!(Full::<&[u8]>::default().data().await.is_none()); assert!(Full::new(&b""[..]).data().await.is_none()); } }