use core::{
pin::Pin,
task::{Context, Poll, ready},
};
use http::{Response, StatusCode};
use http_body::Body;
use pin_project_lite::pin_project;
pin_project! {
pub struct DefinedFuture<F> {
#[pin]
inner: DefinedFutureKind<F>,
}
}
pin_project! {
#[project = DefinedFutureKindProj]
enum DefinedFutureKind<F> {
Proceeding {
#[pin]
future: F,
},
Status {
status: StatusCode
},
}
}
impl<F> DefinedFuture<F> {
pub fn return_status(status: StatusCode) -> Self {
Self {
inner: DefinedFutureKind::Status { status },
}
}
pub fn proceed(future: F) -> Self {
Self {
inner: DefinedFutureKind::Proceeding { future },
}
}
}
impl<B, F, E> Future for DefinedFuture<F>
where
B: Body + Default,
F: Future<Output = Result<Response<B>, E>>,
{
type Output = Result<Response<B>, E>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let response = match self.project().inner.project() {
DefinedFutureKindProj::Proceeding { future } => ready!(future.poll(cx))?,
DefinedFutureKindProj::Status { status } => Response::builder()
.status(*status)
.body(B::default())
.expect("error response should be valid response"),
};
Poll::Ready(Ok(response))
}
}