1use bytes::{Buf, Bytes};
2use http_body::{Body, Frame, SizeHint};
3use pin_project_lite::pin_project;
4use std::borrow::Cow;
5use std::convert::{Infallible, TryFrom};
6use std::pin::Pin;
7use std::task::{Context, Poll};
8
9pin_project! {
10 #[derive(Clone, Copy, Debug)]
12 pub struct Full<D> {
13 data: Option<D>,
14 }
15}
16
17impl<D> Full<D>
18where
19 D: Buf,
20{
21 pub fn new(data: D) -> Self {
23 let data = if data.has_remaining() {
24 Some(data)
25 } else {
26 None
27 };
28 Full { data }
29 }
30}
31
32impl<D> Full<D> {
33 pub fn into_inner(self) -> Option<D> {
46 self.data
47 }
48}
49
50impl<D> Body for Full<D>
51where
52 D: Buf,
53{
54 type Data = D;
55 type Error = Infallible;
56
57 fn poll_frame(
58 mut self: Pin<&mut Self>,
59 _cx: &mut Context<'_>,
60 ) -> Poll<Option<Result<Frame<D>, Self::Error>>> {
61 Poll::Ready(self.data.take().map(|d| Ok(Frame::data(d))))
62 }
63
64 fn is_end_stream(&self) -> bool {
65 self.data.is_none()
66 }
67
68 fn size_hint(&self) -> SizeHint {
69 self.data
70 .as_ref()
71 .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()))
72 .unwrap_or_else(|| SizeHint::with_exact(0))
73 }
74}
75
76impl<D> Default for Full<D>
77where
78 D: Buf,
79{
80 fn default() -> Self {
82 Full { data: None }
83 }
84}
85
86impl<D> From<Bytes> for Full<D>
87where
88 D: Buf + From<Bytes>,
89{
90 fn from(bytes: Bytes) -> Self {
91 Full::new(D::from(bytes))
92 }
93}
94
95impl<D> From<Vec<u8>> for Full<D>
96where
97 D: Buf + From<Vec<u8>>,
98{
99 fn from(vec: Vec<u8>) -> Self {
100 Full::new(D::from(vec))
101 }
102}
103
104impl<D> From<&'static [u8]> for Full<D>
105where
106 D: Buf + From<&'static [u8]>,
107{
108 fn from(slice: &'static [u8]) -> Self {
109 Full::new(D::from(slice))
110 }
111}
112
113impl<D, B> From<Cow<'static, B>> for Full<D>
114where
115 D: Buf + From<&'static B> + From<B::Owned>,
116 B: ToOwned + ?Sized,
117{
118 fn from(cow: Cow<'static, B>) -> Self {
119 match cow {
120 Cow::Borrowed(b) => Full::new(D::from(b)),
121 Cow::Owned(o) => Full::new(D::from(o)),
122 }
123 }
124}
125
126impl<D> From<String> for Full<D>
127where
128 D: Buf + From<String>,
129{
130 fn from(s: String) -> Self {
131 Full::new(D::from(s))
132 }
133}
134
135impl<D> From<&'static str> for Full<D>
136where
137 D: Buf + From<&'static str>,
138{
139 fn from(slice: &'static str) -> Self {
140 Full::new(D::from(slice))
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use super::*;
147 use crate::BodyExt;
148
149 #[tokio::test]
150 async fn full_returns_some() {
151 let mut full = Full::new(&b"hello"[..]);
152 assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64));
153 assert_eq!(
154 full.frame().await.unwrap().unwrap().into_data().unwrap(),
155 &b"hello"[..]
156 );
157 assert!(full.frame().await.is_none());
158 }
159
160 #[tokio::test]
161 async fn empty_full_returns_none() {
162 assert!(Full::<&[u8]>::default().frame().await.is_none());
163 assert!(Full::new(&b""[..]).frame().await.is_none());
164 }
165
166 #[tokio::test]
167 async fn full_into_inner_returns_none_before_poll() {
168 const DATA: &[u8] = b"hello";
169 let full = Full::new(DATA);
170 assert_eq!(
171 full.into_inner(),
172 Some(str::as_bytes("hello")),
173 "`Full::into_inner()` returns `Some(_)` before poll"
174 );
175 }
176
177 #[tokio::test]
178 async fn full_into_inner_returns_none_after_poll() {
179 const DATA: &[u8] = b"hello";
180 let mut full = Full::new(DATA);
181 full.frame().await.expect("a result").expect("a frame");
182 assert_eq!(
183 full.into_inner(),
184 None,
185 "`Full::into_inner()` returns `None` after poll"
186 );
187 }
188}