1 | use bytes::{Buf, Bytes}; |
2 | use http_body::{Body, Frame, SizeHint}; |
3 | use pin_project_lite::pin_project; |
4 | use std::borrow::Cow; |
5 | use std::convert::{Infallible, TryFrom}; |
6 | use std::pin::Pin; |
7 | use std::task::{Context, Poll}; |
8 | |
9 | pin_project! { |
10 | /// A body that consists of a single chunk. |
11 | #[derive (Clone, Copy, Debug)] |
12 | pub struct Full<D> { |
13 | data: Option<D>, |
14 | } |
15 | } |
16 | |
17 | impl<D> Full<D> |
18 | where |
19 | D: Buf, |
20 | { |
21 | /// Create a new `Full`. |
22 | pub fn new(data: D) -> Self { |
23 | let data: Option = if data.has_remaining() { |
24 | Some(data) |
25 | } else { |
26 | None |
27 | }; |
28 | Full { data } |
29 | } |
30 | } |
31 | |
32 | impl<D> Body for Full<D> |
33 | where |
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: D| Ok(Frame::data(buf: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: &D| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap())) |
54 | .unwrap_or_else(|| SizeHint::with_exact(0)) |
55 | } |
56 | } |
57 | |
58 | impl<D> Default for Full<D> |
59 | where |
60 | D: Buf, |
61 | { |
62 | /// Create an empty `Full`. |
63 | fn default() -> Self { |
64 | Full { data: None } |
65 | } |
66 | } |
67 | |
68 | impl<D> From<Bytes> for Full<D> |
69 | where |
70 | D: Buf + From<Bytes>, |
71 | { |
72 | fn from(bytes: Bytes) -> Self { |
73 | Full::new(D::from(bytes)) |
74 | } |
75 | } |
76 | |
77 | impl<D> From<Vec<u8>> for Full<D> |
78 | where |
79 | D: Buf + From<Vec<u8>>, |
80 | { |
81 | fn from(vec: Vec<u8>) -> Self { |
82 | Full::new(D::from(vec)) |
83 | } |
84 | } |
85 | |
86 | impl<D> From<&'static [u8]> for Full<D> |
87 | where |
88 | D: Buf + From<&'static [u8]>, |
89 | { |
90 | fn from(slice: &'static [u8]) -> Self { |
91 | Full::new(D::from(slice)) |
92 | } |
93 | } |
94 | |
95 | impl<D, B> From<Cow<'static, B>> for Full<D> |
96 | where |
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: &B) => Full::new(D::from(b)), |
103 | Cow::Owned(o: ::Owned) => Full::new(D::from(o)), |
104 | } |
105 | } |
106 | } |
107 | |
108 | impl<D> From<String> for Full<D> |
109 | where |
110 | D: Buf + From<String>, |
111 | { |
112 | fn from(s: String) -> Self { |
113 | Full::new(D::from(s)) |
114 | } |
115 | } |
116 | |
117 | impl<D> From<&'static str> for Full<D> |
118 | where |
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)] |
127 | mod 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 | } |
148 | |