timvw_rust_runtime/
body.rs1use std::fmt;
2use std::pin::Pin;
3use std::task::{Context, Poll};
4
5use bytes::Bytes;
6use futures_core::TryStream;
7use futures_util::TryStreamExt;
8use http_body::{Frame, SizeHint};
9use http_body_util::combinators::BoxBody;
10use http_body_util::{BodyExt, StreamBody};
11use sync_wrapper::SyncStream;
12
13use crate::BoxError;
14
15pub struct Body {
20 kind: Kind,
21}
22
23enum Kind {
24 Full(Option<Bytes>),
25 Stream(BoxBody<Bytes, BoxError>),
26}
27
28impl Body {
29 pub fn empty() -> Self {
31 Self {
32 kind: Kind::Full(None),
33 }
34 }
35
36 pub fn wrap<B>(body: B) -> Self
38 where
39 B: http_body::Body + Send + Sync + 'static,
40 B::Data: Into<Bytes>,
41 B::Error: Into<BoxError>,
42 {
43 Self {
44 kind: Kind::Stream(
45 body.map_frame(|frame| frame.map_data(Into::into))
46 .map_err(Into::into)
47 .boxed(),
48 ),
49 }
50 }
51
52 pub fn wrap_stream<S>(stream: S) -> Self
54 where
55 S: TryStream + Send + 'static,
56 S::Ok: Into<Bytes>,
57 S::Error: Into<BoxError>,
58 {
59 let frames = SyncStream::new(
60 stream
61 .into_stream()
62 .map_ok(|chunk| Frame::data(chunk.into()))
63 .map_err(Into::into),
64 );
65 Self {
66 kind: Kind::Stream(StreamBody::new(frames).boxed()),
67 }
68 }
69
70 pub fn try_clone(&self) -> Option<Self> {
72 match &self.kind {
73 Kind::Full(bytes) => Some(Self {
74 kind: Kind::Full(bytes.clone()),
75 }),
76 Kind::Stream(_) => None,
77 }
78 }
79
80 pub fn as_bytes(&self) -> Option<&[u8]> {
82 match &self.kind {
83 Kind::Full(bytes) => Some(bytes.as_deref().unwrap_or_default()),
84 Kind::Stream(_) => None,
85 }
86 }
87
88 pub async fn collect_bytes(self) -> Result<Bytes, BoxError> {
90 match self.kind {
91 Kind::Full(bytes) => Ok(bytes.unwrap_or_default()),
92 Kind::Stream(body) => Ok(body.collect().await?.to_bytes()),
93 }
94 }
95}
96
97impl Default for Body {
98 fn default() -> Self {
99 Self::empty()
100 }
101}
102
103impl fmt::Debug for Body {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 match &self.kind {
106 Kind::Full(bytes) => f
107 .debug_struct("Body")
108 .field("len", &bytes.as_ref().map_or(0, Bytes::len))
109 .finish(),
110 Kind::Stream(_) => f.debug_struct("Body").field("stream", &true).finish(),
111 }
112 }
113}
114
115impl http_body::Body for Body {
116 type Data = Bytes;
117 type Error = BoxError;
118
119 fn poll_frame(
120 self: Pin<&mut Self>,
121 cx: &mut Context<'_>,
122 ) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
123 match &mut self.get_mut().kind {
124 Kind::Full(bytes) => Poll::Ready(
125 bytes
126 .take()
127 .filter(|b| !b.is_empty())
128 .map(|b| Ok(Frame::data(b))),
129 ),
130 Kind::Stream(body) => Pin::new(body).poll_frame(cx),
131 }
132 }
133
134 fn is_end_stream(&self) -> bool {
135 match &self.kind {
136 Kind::Full(bytes) => bytes.as_ref().is_none_or(Bytes::is_empty),
137 Kind::Stream(body) => body.is_end_stream(),
138 }
139 }
140
141 fn size_hint(&self) -> SizeHint {
142 match &self.kind {
143 Kind::Full(bytes) => SizeHint::with_exact(bytes.as_ref().map_or(0, |b| b.len() as u64)),
144 Kind::Stream(body) => body.size_hint(),
145 }
146 }
147}
148
149impl From<Bytes> for Body {
150 fn from(bytes: Bytes) -> Self {
151 Self {
152 kind: Kind::Full(Some(bytes)),
153 }
154 }
155}
156
157impl From<Vec<u8>> for Body {
158 fn from(bytes: Vec<u8>) -> Self {
159 Bytes::from(bytes).into()
160 }
161}
162
163impl From<String> for Body {
164 fn from(text: String) -> Self {
165 Bytes::from(text).into()
166 }
167}
168
169impl From<&'static str> for Body {
170 fn from(text: &'static str) -> Self {
171 Bytes::from_static(text.as_bytes()).into()
172 }
173}
174
175impl From<&'static [u8]> for Body {
176 fn from(bytes: &'static [u8]) -> Self {
177 Bytes::from_static(bytes).into()
178 }
179}
180
181#[cfg(test)]
182mod tests {
183 use super::*;
184
185 #[tokio::test]
186 async fn bytes_clone_and_read() {
187 let body = Body::from("hello");
188 let copy = body.try_clone().expect("bytes can be cloned");
189 assert_eq!(body.collect_bytes().await.unwrap(), "hello");
190 assert_eq!(copy.as_bytes(), Some(&b"hello"[..]));
191 }
192
193 #[tokio::test]
194 async fn streams_are_read_once() {
195 let chunks = futures_util::stream::iter(vec![
196 Ok::<_, std::io::Error>(Bytes::from("a")),
197 Ok(Bytes::from("b")),
198 ]);
199 let body = Body::wrap_stream(chunks);
200 assert!(body.try_clone().is_none());
201 assert_eq!(body.collect_bytes().await.unwrap(), "ab");
202 }
203
204 #[test]
205 fn empty_is_end_of_stream() {
206 assert!(http_body::Body::is_end_stream(&Body::empty()));
207 assert_eq!(
208 http_body::Body::size_hint(&Body::from("abc")).exact(),
209 Some(3)
210 );
211 }
212}