hyper_utils/http_body_util/
full.rs1use std::{
2 borrow::Cow,
3 convert::{Infallible, TryFrom},
4 pin::Pin,
5 task::{Context, Poll},
6};
7
8use bytes::{Buf, Bytes};
9use hyper::body::{Body, Frame, SizeHint};
10use pin_project_lite::pin_project;
11
12pin_project! {
13 #[derive(Clone, Copy, Debug)]
15 pub struct Full<D> {
16 data: Option<D>,
17 }
18}
19
20impl<D> Full<D>
21where
22 D: Buf,
23{
24 pub fn new(data: D) -> Self {
26 let data = if data.has_remaining() { Some(data) } else { None };
27 Full {
28 data,
29 }
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_frame(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Result<Frame<D>, Self::Error>>> {
41 Poll::Ready(self.data.take().map(|d| Ok(Frame::data(d))))
42 }
43
44 fn is_end_stream(&self) -> bool {
45 self.data.is_none()
46 }
47
48 fn size_hint(&self) -> SizeHint {
49 self.data
50 .as_ref()
51 .map(|data| SizeHint::with_exact(u64::try_from(data.remaining()).unwrap()))
52 .unwrap_or_else(|| SizeHint::with_exact(0))
53 }
54}
55
56impl<D> Default for Full<D>
57where
58 D: Buf,
59{
60 fn default() -> Self {
62 Full {
63 data: None,
64 }
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::http_body_util::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!(full.frame().await.unwrap().unwrap().into_data().unwrap(), &b"hello"[..]);
136 assert!(full.frame().await.is_none());
137 }
138
139 #[tokio::test]
140 async fn empty_full_returns_none() {
141 assert!(Full::<&[u8]>::default().frame().await.is_none());
142 assert!(Full::new(&b""[..]).frame().await.is_none());
143 }
144}