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> Body for Full<D>
33where
34 D: Buf,
35{
36 type Data = D;
37 type Error = Infallible;
38
39 fn poll_frame(
40 mut self: Pin<&mut Self>,
41 _cx: &mut Context<'_>,
42 ) -> Poll<Option<Result<Frame<D>, Self::Error>>> {
43 Poll::Ready(self.data.take().map(|d| Ok(Frame::data(d))))
44 }
45
46 fn is_end_stream(&self) -> bool {
47 self.data.is_none()
48 }
49
50 fn size_hint(&self) -> SizeHint {
51 self.data
52 .as_ref()
53 .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()))
54 .unwrap_or_else(|| SizeHint::with_exact(0))
55 }
56}
57
58impl<D> Default for Full<D>
59where
60 D: Buf,
61{
62 fn default() -> Self {
64 Full { data: None }
65 }
66}
67
68impl<D> From<Bytes> for Full<D>
69where
70 D: Buf + From<Bytes>,
71{
72 fn from(bytes: Bytes) -> Self {
73 Full::new(D::from(bytes))
74 }
75}
76
77impl<D> From<Vec<u8>> for Full<D>
78where
79 D: Buf + From<Vec<u8>>,
80{
81 fn from(vec: Vec<u8>) -> Self {
82 Full::new(D::from(vec))
83 }
84}
85
86impl<D> From<&'static [u8]> for Full<D>
87where
88 D: Buf + From<&'static [u8]>,
89{
90 fn from(slice: &'static [u8]) -> Self {
91 Full::new(D::from(slice))
92 }
93}
94
95impl<D, B> From<Cow<'static, B>> for Full<D>
96where
97 D: Buf + From<&'static B> + From<B::Owned>,
98 B: ToOwned + ?Sized,
99{
100 fn from(cow: Cow<'static, B>) -> Self {
101 match cow {
102 Cow::Borrowed(b) => Full::new(D::from(b)),
103 Cow::Owned(o) => Full::new(D::from(o)),
104 }
105 }
106}
107
108impl<D> From<String> for Full<D>
109where
110 D: Buf + From<String>,
111{
112 fn from(s: String) -> Self {
113 Full::new(D::from(s))
114 }
115}
116
117impl<D> From<&'static str> for Full<D>
118where
119 D: Buf + From<&'static str>,
120{
121 fn from(slice: &'static str) -> Self {
122 Full::new(D::from(slice))
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use crate::BodyExt;
130
131 #[tokio::test]
132 async fn full_returns_some() {
133 let mut full = Full::new(&b"hello"[..]);
134 assert_eq!(full.size_hint().exact(), Some(b"hello".len() as u64));
135 assert_eq!(
136 full.frame().await.unwrap().unwrap().into_data().unwrap(),
137 &b"hello"[..]
138 );
139 assert!(full.frame().await.is_none());
140 }
141
142 #[tokio::test]
143 async fn empty_full_returns_none() {
144 assert!(Full::<&[u8]>::default().frame().await.is_none());
145 assert!(Full::new(&b""[..]).frame().await.is_none());
146 }
147}