use std::pin::{Pin, pin};
use std::task::{Context, Poll};
use http_body::{Frame, SizeHint};
use http_body_util::combinators::UnsyncBoxBody;
use crate::response::body::body_::boxed::boxed;
use crate::response::body::raw::RawBody;
use super::raw::Bytes;
#[derive(Debug)]
pub struct ResponseBody(UnsyncBoxBody<Bytes, crate::Error>);
impl ResponseBody {
pub fn new<B>(body: B) -> Self
where
B: RawBody<Data = Bytes> + Send + 'static,
<B as RawBody>::Error: Into<Box<dyn std::error::Error + Send + Sync>>,
{
boxed(body)
}
}
impl RawBody for ResponseBody {
type Data = Bytes;
type Error = crate::Error;
fn poll_frame(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
) -> Poll<Option<Result<Frame<Self::Data>, Self::Error>>> {
pin!(&mut self.0).as_mut().poll_frame(cx)
}
fn is_end_stream(&self) -> bool {
self.0.is_end_stream()
}
fn size_hint(&self) -> SizeHint {
self.0.size_hint()
}
}
impl Default for ResponseBody {
fn default() -> Self {
ResponseBody::new(super::raw::Empty::new())
}
}
mod boxed {
use http_body_util::BodyExt;
use crate::Error;
use crate::response::body::raw::RawBody;
use super::{Bytes, ResponseBody};
pub(super) fn boxed<B>(body: B) -> ResponseBody
where
B: RawBody<Data = Bytes> + Send + 'static,
B::Error: Into<Box<dyn std::error::Error + Sync + Send>>,
{
ResponseBody(
try_downcast(body).unwrap_or_else(|body| body.map_err(Error::new).boxed_unsync()),
)
}
fn try_downcast<T, K>(k: K) -> Result<T, K>
where
T: 'static,
K: Send + 'static,
{
let mut k = Some(k);
match <dyn std::any::Any>::downcast_mut::<Option<T>>(&mut k) {
Some(k) => Ok(k.take().unwrap()),
_ => Err(k.unwrap()),
}
}
#[test]
fn test_try_downcast() {
assert_eq!(try_downcast::<i32, _>(5_u32), Err(5_u32));
assert_eq!(try_downcast::<i32, _>(5_i32), Ok(5_i32));
}
}