1use std::{pin::Pin, task::Poll};
28
29use http_body_util::BodyExt as _;
30
31type BoxBody = http_body_util::combinators::UnsyncBoxBody<bytes::Bytes, crate::Status>;
33
34#[derive(Debug)]
36pub struct Body {
37 kind: Kind,
38}
39
40#[derive(Debug)]
41enum Kind {
42 Empty,
43 Wrap(BoxBody),
44}
45
46impl Body {
47 fn from_kind(kind: Kind) -> Self {
48 Self { kind }
49 }
50
51 pub const fn empty() -> Self {
53 Self { kind: Kind::Empty }
54 }
55
56 pub fn new<B>(body: B) -> Self
58 where
59 B: http_body::Body<Data = bytes::Bytes> + Send + 'static,
60 B::Error: Into<crate::BoxError>,
61 {
62 if body.is_end_stream() {
63 return Self::empty();
64 }
65
66 let mut body = Some(body);
67
68 if let Some(body) = <dyn std::any::Any>::downcast_mut::<Option<Body>>(&mut body) {
69 return body.take().unwrap();
70 }
71
72 if let Some(body) = <dyn std::any::Any>::downcast_mut::<Option<BoxBody>>(&mut body) {
73 return Self::from_kind(Kind::Wrap(body.take().unwrap()));
74 }
75
76 let body = body
77 .unwrap()
78 .map_err(crate::Status::map_error)
79 .boxed_unsync();
80
81 Self::from_kind(Kind::Wrap(body))
82 }
83}
84
85impl Default for Body {
86 fn default() -> Self {
87 Self::empty()
88 }
89}
90
91impl http_body::Body for Body {
92 type Data = bytes::Bytes;
93 type Error = crate::Status;
94
95 fn poll_frame(
96 mut self: std::pin::Pin<&mut Self>,
97 cx: &mut std::task::Context<'_>,
98 ) -> Poll<Option<Result<http_body::Frame<Self::Data>, Self::Error>>> {
99 match &mut self.kind {
100 Kind::Empty => Poll::Ready(None),
101 Kind::Wrap(body) => Pin::new(body).poll_frame(cx),
102 }
103 }
104
105 fn size_hint(&self) -> http_body::SizeHint {
106 match &self.kind {
107 Kind::Empty => http_body::SizeHint::with_exact(0),
108 Kind::Wrap(body) => body.size_hint(),
109 }
110 }
111
112 fn is_end_stream(&self) -> bool {
113 match &self.kind {
114 Kind::Empty => true,
115 Kind::Wrap(body) => body.is_end_stream(),
116 }
117 }
118}