1use std::{
2 convert::Infallible,
3 pin::{pin, Pin},
4 task::Poll,
5};
6
7use bytes::Bytes;
8use futures_core::Stream;
9use http_body::{Frame, SizeHint};
10
11pub enum Body {
30 Full(Box<[u8]>),
31 Stream(Pin<Box<dyn Stream<Item = Vec<u8>> + Send>>),
32}
33
34impl http_body::Body for Body {
35 type Data = Bytes;
36 type Error = Infallible;
37
38 fn size_hint(&self) -> http_body::SizeHint {
39 match self {
40 Body::Full(value) => SizeHint::with_exact(value.len() as u64),
41 Body::Stream(body) => {
42 let (lower, higher) = body.size_hint();
43 let mut size_hint = SizeHint::default();
44 size_hint.set_lower(lower as u64);
45 if let Some(higher) = higher {
46 size_hint.set_upper(higher as u64);
47 }
48 size_hint
49 }
50 }
51 }
52
53 fn poll_frame(
54 self: Pin<&mut Self>,
55 cx: &mut std::task::Context<'_>,
56 ) -> std::task::Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>>
57 {
58 match self.get_mut() {
59 Body::Full(body) => {
60 Poll::Ready(Some(Ok(Frame::data(Bytes::from(body.clone())))))
61 }
62 Body::Stream(body) => {
63 let value = pin!(body);
64 let value = match value.poll_next(cx) {
65 Poll::Pending => return Poll::Pending,
66 Poll::Ready(value) => match value {
67 None => return Poll::Ready(None),
68 Some(value) => value,
69 },
70 };
71
72 let frame = Frame::data(Bytes::from(value));
73 Poll::Ready(Some(Ok(frame)))
74 }
75 }
76 }
77
78 fn is_end_stream(&self) -> bool {
79 true
81 }
82}
83
84impl From<String> for Body {
85 fn from(value: String) -> Self {
86 Self::Full(value.as_bytes().into())
87 }
88}
89
90impl From<()> for Body {
91 fn from(_: ()) -> Self {
92 Self::Full([].into())
93 }
94}
95
96impl<'a> From<&'a str> for Body {
97 fn from(value: &'a str) -> Self {
98 Self::Full(value.as_bytes().into())
99 }
100}
101
102impl From<Box<[u8]>> for Body {
103 fn from(value: Box<[u8]>) -> Self {
104 Self::Full(value)
105 }
106}
107
108impl From<Vec<u8>> for Body {
109 fn from(value: Vec<u8>) -> Self {
110 Self::Full(value.into())
111 }
112}
113
114impl From<&'_ [u8]> for Body {
115 fn from(value: &'_ [u8]) -> Self {
116 Self::Full(value.into())
117 }
118}
119
120macro_rules! impl_tostring {
142 ($( $type:ident )*) => {
143 $(impl From<$type> for Body {
144 fn from(value: $type) -> Self {
145 let body_str = value.to_string();
146 Self::Full(body_str.as_bytes().into())
147 }
148 })*
149 };
150}
151
152impl_tostring! { usize i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 }