use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use http_body::{Frame, SizeHint};
use http_body_util::combinators::UnsyncBoxBody;
use http_body_util::BodyExt;
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
pub struct Body(UnsyncBoxBody<Bytes, BoxError>);
impl Body {
pub fn empty() -> Self {
Self::new(http_body_util::Empty::<Bytes>::new())
}
pub fn full<B: Into<Bytes>>(bytes: B) -> Self {
Self::new(http_body_util::Full::new(bytes.into()))
}
pub fn new<B>(body: B) -> Self
where
B: http_body::Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>,
{
try_downcast(body).unwrap_or_else(|body| Self(body.map_err(Into::into).boxed_unsync()))
}
}
#[allow(clippy::unwrap_used)] fn try_downcast<T: 'static, K: Send + 'static>(k: K) -> Result<T, K> {
let mut k = Some(k);
if let Some(k) = <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
Ok(k.take().expect("downcast succeeded but value was None"))
} else {
Err(k.expect("downcast failed but value was None"))
}
}
impl Default for Body {
fn default() -> Self {
Self::empty()
}
}
impl http_body::Body for Body {
type Data = Bytes;
type Error = BoxError;
fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
Pin::new(&mut self.get_mut().0).poll_frame(cx)
}
fn is_end_stream(&self) -> bool {
self.0.is_end_stream()
}
fn size_hint(&self) -> SizeHint {
self.0.size_hint()
}
}