1use futures::prelude::*;
8use std::pin::Pin;
9use std::task::{Context, Poll};
10
11pub struct BodySender {
13 tx: futures::channel::mpsc::Sender<Result<hyper::body::Bytes, std::io::Error>>,
14}
15
16impl BodySender {
17 #[allow(clippy::result_unit_err)]
19 pub fn try_send_data(&mut self, data: hyper::body::Bytes) -> Result<(), ()> {
20 self.tx.try_send(Ok(data)).map_err(|_| ())
21 }
22}
23
24#[allow(clippy::type_complexity)]
26pub enum Body {
27 Empty(http_body_util::Empty<hyper::body::Bytes>),
28 Full(http_body_util::Full<hyper::body::Bytes>),
29 Stream(
30 http_body_util::StreamBody<
31 Pin<
32 Box<
33 dyn Stream<
34 Item = Result<hyper::body::Frame<hyper::body::Bytes>, std::io::Error>,
35 > + Send
36 + Sync,
37 >,
38 >,
39 >,
40 ),
41 #[cfg(not(target_os = "fuchsia"))]
42 Sse(http_sse::Body),
43}
44
45impl std::fmt::Debug for Body {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 match self {
48 Body::Empty(_) => f.debug_tuple("Empty").finish(),
49 Body::Full(_) => f.debug_tuple("Full").finish(),
50 Body::Stream(_) => f.debug_tuple("Stream").finish(),
51 #[cfg(not(target_os = "fuchsia"))]
52 Body::Sse(_) => f.debug_tuple("Sse").finish(),
53 }
54 }
55}
56
57impl Body {
58 pub fn empty() -> Self {
60 Body::Empty(http_body_util::Empty::new())
61 }
62
63 pub fn wrap_stream<S, O, E>(stream: S) -> Self
65 where
66 S: Stream<Item = Result<O, E>> + Send + Sync + 'static,
67 O: Into<hyper::body::Bytes>,
68 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
69 {
70 let stream = stream.map(|res| match res {
71 Ok(data) => Ok(hyper::body::Frame::data(data.into())),
72 Err(e) => Err(std::io::Error::other(e)),
73 });
74 Body::Stream(http_body_util::StreamBody::new(Box::pin(stream)))
75 }
76
77 pub fn channel() -> (BodySender, Self) {
79 let (tx, rx) = futures::channel::mpsc::channel(1);
80 (BodySender { tx }, Self::wrap_stream(rx))
81 }
82}
83
84impl From<Vec<u8>> for Body {
85 fn from(data: Vec<u8>) -> Self {
86 Body::Full(http_body_util::Full::new(data.into()))
87 }
88}
89
90impl From<String> for Body {
91 fn from(data: String) -> Self {
92 Body::Full(http_body_util::Full::new(data.into()))
93 }
94}
95
96impl From<&'static str> for Body {
97 fn from(data: &'static str) -> Self {
98 Body::Full(http_body_util::Full::new(data.into()))
99 }
100}
101
102#[cfg(not(target_os = "fuchsia"))]
103impl From<http_sse::Body> for Body {
104 fn from(body: http_sse::Body) -> Self {
105 Body::Sse(body)
106 }
107}
108
109impl hyper::body::Body for Body {
110 type Data = hyper::body::Bytes;
111 type Error = Box<dyn std::error::Error + Send + Sync + 'static>;
112
113 fn poll_frame(
114 self: Pin<&mut Self>,
115 cx: &mut Context<'_>,
116 ) -> Poll<Option<Result<hyper::body::Frame<Self::Data>, Self::Error>>> {
117 match self.get_mut() {
118 Body::Empty(b) => Pin::new(b).poll_frame(cx).map_err(|e| match e {}),
119 Body::Full(b) => Pin::new(b).poll_frame(cx).map_err(|e| match e {}),
120 Body::Stream(b) => Pin::new(b).poll_frame(cx).map_err(|e| Box::new(e) as _),
121 #[cfg(not(target_os = "fuchsia"))]
122 Body::Sse(b) => {
123 Pin::new(b).poll_frame(cx).map_err(|e| Box::new(std::io::Error::other(e)) as _)
124 }
125 }
126 }
127}