use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use bytes::Bytes;
use http_body_util::{BodyExt, Collected};
use serde::de::DeserializeOwned;
mod error;
mod future;
use crate::client;
use crate::error::Error;
use crate::types::ErrorResponse;
use self::error::BodyErrorKind;
pub use self::error::BodyError;
pub use self::future::ResponseFuture;
pub(crate) type Output<T> = Result<Response<T>, Error>;
#[non_exhaustive]
pub struct NoContent;
pub struct Response<T> {
inner: client::service::Response,
phantom: PhantomData<T>,
}
impl<T> Response<T> {
pub(crate) const fn new(inner: client::service::Response) -> Self {
Self {
inner,
phantom: PhantomData,
}
}
pub fn headers(&self) -> &http::HeaderMap {
self.inner.headers()
}
pub fn status(&self) -> http::StatusCode {
self.inner.status()
}
pub fn bytes(self) -> BytesFuture {
let body = self.inner.into_body();
let fut = async {
body.collect()
.await
.map(Collected::to_bytes)
.map_err(|err| BodyError::new(BodyErrorKind::Loading, Some(err)))
};
BytesFuture {
inner: Box::pin(fut),
}
}
pub fn text(self) -> TextFuture {
TextFuture::new(self.bytes())
}
fn error(self) -> ErrorResponseFuture {
ErrorResponseFuture::new(self.bytes())
}
}
impl<T: DeserializeOwned> Response<T> {
pub fn data(self) -> DataFuture<T> {
DataFuture::new(self.bytes())
}
}
pub struct BytesFuture {
inner: Pin<Box<dyn Future<Output = Result<Bytes, BodyError>> + Send + Sync>>,
}
impl Future for BytesFuture {
type Output = Result<Bytes, BodyError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.inner.as_mut().poll(cx)
}
}
pub struct DataFuture<T> {
inner: BytesFuture,
phantom: PhantomData<T>,
}
impl<T> DataFuture<T> {
const fn new(bytes: BytesFuture) -> Self {
Self {
inner: bytes,
phantom: PhantomData,
}
}
}
impl<T: DeserializeOwned + Unpin> Future for DataFuture<T> {
type Output = Result<T, BodyError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.inner).poll(cx) {
Poll::Ready(Ok(bytes)) => Poll::Ready(
serde_json::from_slice(&bytes).map_err(|err| BodyError::decode(bytes, err)),
),
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}
}
pub struct TextFuture {
inner: BytesFuture,
}
impl TextFuture {
const fn new(bytes: BytesFuture) -> Self {
Self { inner: bytes }
}
}
impl Future for TextFuture {
type Output = Result<String, BodyError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
match Pin::new(&mut self.inner).poll(cx) {
Poll::Ready(Ok(bytes)) => {
Poll::Ready(String::from_utf8(bytes.to_vec()).map_err(|err| {
let utf8_error = err.utf8_error();
BodyError::invalid_utf8(err.into_bytes(), utf8_error)
}))
}
Poll::Ready(Err(err)) => Poll::Ready(Err(err)),
Poll::Pending => Poll::Pending,
}
}
}
struct ErrorResponseFuture {
inner: DataFuture<ErrorResponse>,
}
impl ErrorResponseFuture {
const fn new(bytes: BytesFuture) -> Self {
Self {
inner: DataFuture::new(bytes),
}
}
}
impl Future for ErrorResponseFuture {
type Output = Result<ErrorResponse, BodyError>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
Pin::new(&mut self.inner).poll(cx)
}
}