use std::convert::Infallible;
use std::fmt::Debug;
use std::pin::Pin;
use std::task::Context;
use std::task::Poll;
use anyhow::Result;
use bytes::Bytes;
use futures_util::Stream;
use futures_util::TryStream;
use futures_util::TryStreamExt;
use http_body::Body;
use http_body::Frame;
use http_body::SizeHint;
use http_body_util::BodyExt;
use http_body_util::Empty;
use http_body_util::Full;
use http_body_util::StreamBody;
use crate::types::BoxBody;
use crate::types::BoxError;
#[allow(dead_code)]
enum BodyInner {
Full(Full<Bytes>),
Empty(Empty<Bytes>),
Incoming(hyper::body::Incoming),
Boxed(BoxBody),
}
pub struct TakoBody(BodyInner);
impl std::fmt::Debug for TakoBody {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TakoBody").finish_non_exhaustive()
}
}
impl TakoBody {
#[inline]
pub fn new<B>(body: B) -> Self
where
B: Body<Data = Bytes> + Send + 'static,
B::Error: Into<BoxError>,
{
Self(BodyInner::Boxed(body.map_err(|e| e.into()).boxed_unsync()))
}
#[inline]
pub fn full(body: Full<Bytes>) -> Self {
Self(BodyInner::Full(body))
}
#[inline]
#[allow(dead_code)]
pub(crate) fn incoming(body: hyper::body::Incoming) -> Self {
Self(BodyInner::Incoming(body))
}
#[inline]
pub fn from_stream<S, E>(stream: S) -> Self
where
S: Stream<Item = Result<Bytes, E>> + Send + 'static,
E: Into<BoxError> + Debug + 'static,
{
let stream = stream.map_err(Into::into).map_ok(http_body::Frame::data);
let body = StreamBody::new(stream).boxed_unsync();
Self(BodyInner::Boxed(body))
}
#[inline]
pub fn from_try_stream<S, E>(stream: S) -> Self
where
S: TryStream<Ok = Frame<Bytes>, Error = E> + Send + 'static,
E: Into<BoxError> + 'static,
{
let body = StreamBody::new(stream.map_err(Into::into)).boxed_unsync();
Self(BodyInner::Boxed(body))
}
#[inline]
#[must_use]
pub fn empty() -> Self {
Self(BodyInner::Empty(Empty::new()))
}
}
impl Default for TakoBody {
fn default() -> Self {
Self::empty()
}
}
impl From<()> for TakoBody {
fn from(_: ()) -> Self {
Self::empty()
}
}
impl From<&str> for TakoBody {
fn from(buf: &str) -> Self {
Self::full(Full::from(Bytes::from(buf.to_owned())))
}
}
impl From<String> for TakoBody {
fn from(buf: String) -> Self {
Self::full(Full::from(Bytes::from(buf)))
}
}
impl From<Vec<u8>> for TakoBody {
fn from(buf: Vec<u8>) -> Self {
Self::full(Full::from(Bytes::from(buf)))
}
}
impl From<Bytes> for TakoBody {
fn from(buf: Bytes) -> Self {
Self::full(Full::from(buf))
}
}
#[inline]
fn map_infallible_frame(
poll: Poll<Option<core::result::Result<Frame<Bytes>, Infallible>>>,
) -> Poll<Option<core::result::Result<Frame<Bytes>, BoxError>>> {
poll.map(|opt| opt.map(|res| res.map_err(|e| match e {})))
}
#[inline]
fn map_hyper_frame(
poll: Poll<Option<core::result::Result<Frame<Bytes>, hyper::Error>>>,
) -> Poll<Option<core::result::Result<Frame<Bytes>, BoxError>>> {
poll.map(|opt| opt.map(|res| res.map_err(Into::into)))
}
impl Body for TakoBody {
type Data = Bytes;
type Error = BoxError;
#[inline]
fn poll_frame(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<core::result::Result<Frame<Self::Data>, Self::Error>>> {
match &mut self.get_mut().0 {
BodyInner::Full(body) => map_infallible_frame(Pin::new(body).poll_frame(cx)),
BodyInner::Empty(body) => map_infallible_frame(Pin::new(body).poll_frame(cx)),
BodyInner::Incoming(body) => map_hyper_frame(Pin::new(body).poll_frame(cx)),
BodyInner::Boxed(body) => Pin::new(body).poll_frame(cx),
}
}
#[inline]
fn size_hint(&self) -> SizeHint {
match &self.0 {
BodyInner::Full(body) => body.size_hint(),
BodyInner::Empty(body) => body.size_hint(),
BodyInner::Incoming(body) => body.size_hint(),
BodyInner::Boxed(body) => body.size_hint(),
}
}
#[inline]
fn is_end_stream(&self) -> bool {
match &self.0 {
BodyInner::Full(body) => body.is_end_stream(),
BodyInner::Empty(body) => body.is_end_stream(),
BodyInner::Incoming(body) => body.is_end_stream(),
BodyInner::Boxed(body) => body.is_end_stream(),
}
}
}