summaryrefslogtreecommitdiffstats
path: root/third_party/rust/http-body/src/full.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/http-body/src/full.rs')
-rw-r--r--third_party/rust/http-body/src/full.rs151
1 files changed, 151 insertions, 0 deletions
diff --git a/third_party/rust/http-body/src/full.rs b/third_party/rust/http-body/src/full.rs
new file mode 100644
index 0000000000..f1d063b0ae
--- /dev/null
+++ b/third_party/rust/http-body/src/full.rs
@@ -0,0 +1,151 @@
+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<D> {
+ data: Option<D>,
+ }
+}
+
+impl<D> Full<D>
+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<D> Body for Full<D>
+where
+ D: Buf,
+{
+ type Data = D;
+ type Error = Infallible;
+
+ fn poll_data(
+ mut self: Pin<&mut Self>,
+ _cx: &mut Context<'_>,
+ ) -> Poll<Option<Result<D, Self::Error>>> {
+ Poll::Ready(self.data.take().map(Ok))
+ }
+
+ fn poll_trailers(
+ self: Pin<&mut Self>,
+ _cx: &mut Context<'_>,
+ ) -> Poll<Result<Option<HeaderMap>, 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<D> Default for Full<D>
+where
+ D: Buf,
+{
+ /// Create an empty `Full`.
+ fn default() -> Self {
+ Full { data: None }
+ }
+}
+
+impl<D> From<Bytes> for Full<D>
+where
+ D: Buf + From<Bytes>,
+{
+ fn from(bytes: Bytes) -> Self {
+ Full::new(D::from(bytes))
+ }
+}
+
+impl<D> From<Vec<u8>> for Full<D>
+where
+ D: Buf + From<Vec<u8>>,
+{
+ fn from(vec: Vec<u8>) -> Self {
+ Full::new(D::from(vec))
+ }
+}
+
+impl<D> From<&'static [u8]> for Full<D>
+where
+ D: Buf + From<&'static [u8]>,
+{
+ fn from(slice: &'static [u8]) -> Self {
+ Full::new(D::from(slice))
+ }
+}
+
+impl<D, B> From<Cow<'static, B>> for Full<D>
+where
+ D: Buf + From<&'static B> + From<B::Owned>,
+ 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<D> From<String> for Full<D>
+where
+ D: Buf + From<String>,
+{
+ fn from(s: String) -> Self {
+ Full::new(D::from(s))
+ }
+}
+
+impl<D> From<&'static str> for Full<D>
+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());
+ }
+}