1use crate::{Body, SizeHint};
2use bytes::{Buf, Bytes};
3use http::HeaderMap;
4use pin_project_lite::pin_project;
5use std::borrow::Cow;
6use std::convert::{Infallible, TryFrom};
7use std::pin::Pin;
8use std::task::{Context, Poll};
9
10pin_project! {
11 /// A body that consists of a single chunk.
12 #[derive(Clone, Copy, Debug)]
13 pub struct Full<D> {
14 data: Option<D>,
15 }
16}
17
18impl<D> Full<D>
19where
20 D: Buf,
21{
22 /// Create a new `Full`.
23 pub fn new(data: D) -> Self {
24 let data: Option = if data.has_remaining() {
25 Some(data)
26 } else {
27 None
28 };
29 Full { data }
30 }
31}
32
33impl<D> Body for Full<D>
34where
35 D: Buf,
36{
37 type Data = D;
38 type Error = Infallible;
39
40 fn poll_data(
41 mut self: Pin<&mut Self>,
42 _cx: &mut Context<'_>,
43 ) -> Poll<Option<Result<D, Self::Error>>> {
44 Poll::Ready(self.data.take().map(Ok))
45 }
46
47 fn poll_trailers(
48 self: Pin<&mut Self>,
49 _cx: &mut Context<'_>,
50 ) -> Poll<Result<Option<HeaderMap>, Self::Error>> {
51 Poll::Ready(Ok(None))
52 }
53
54 fn is_end_stream(&self) -> bool {
55 self.data.is_none()
56 }
57
58 fn size_hint(&self) -> SizeHint {
59 self.data
60 .as_ref()
61 .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()))
62 .unwrap_or_else(|| SizeHint::with_exact(0))
63 }
64}
65
66impl<D> Default for Full<D>
67where
68 D: Buf,
69{
70 /// Create an empty `Full`.
71 fn default() -> Self {
72 Full { data: None }
73 }
74}
75
76impl<D> From<Bytes> for Full<D>
77where
78 D: Buf + From<Bytes>,
79{
80 fn from(bytes: Bytes) -> Self {
81 Full::new(D::from(bytes))
82 }
83}
84
85impl<D> From<Vec<u8>> for Full<D>
86where
87 D: Buf + From<Vec<u8>>,
88{
89 fn from(vec: Vec<u8>) -> Self {
90 Full::new(D::from(vec))
91 }
92}
93
94impl<D> From<&'static [u8]> for Full<D>
95where
96 D: Buf + From<&'static [u8]>,
97{
98 fn from(slice: &'static [u8]) -> Self {
99 Full::new(D::from(slice))
100 }
101}
102
103impl<D, B> From<Cow<'static, B>> for Full<D>
104where
105 D: Buf + From<&'static B> + From<B::Owned>,
106 B: ToOwned + ?Sized,
107{
108 fn from(cow: Cow<'static, B>) -> Self {
109 match cow {
110 Cow::Borrowed(b: &B) => Full::new(D::from(b)),
111 Cow::Owned(o: ::Owned) => Full::new(D::from(o)),
112 }
113 }
114}
115
116impl<D> From<String> for Full<D>
117where
118 D: Buf + From<String>,
119{
120 fn from(s: String) -> Self {
121 Full::new(D::from(s))
122 }
123}
124
125impl<D> From<&'static str> for Full<D>
126where
127 D: Buf + From<&'static str>,
128{
129 fn from(slice: &'static str) -> Self {
130 Full::new(D::from(slice))
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[tokio::test]
139 async fn full_returns_some() {
140 let mut full = Full::new(&b"hello"[..]);
141 assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64));
142 assert_eq!(full.data().await, Some(Ok(&b"hello"[..])));
143 assert!(full.data().await.is_none());
144 }
145
146 #[tokio::test]
147 async fn empty_full_returns_none() {
148 assert!(Full::<&[u8]>::default().data().await.is_none());
149 assert!(Full::new(&b""[..]).data().await.is_none());
150 }
151}
152