traq_bot_http/handler/
future.rsuse std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
use futures_core::ready;
use http::{Response, StatusCode};
use http_body::Body;
use pin_project_lite::pin_project;
use tower_service::Service;
use crate::error::{Error, Result};
use crate::events::Event;
use crate::parser::ParseRequest;
pin_project! {
#[must_use]
#[project = WrapErrorFutureProject]
#[derive(Debug)]
pub struct WrapErrorFuture<F, E> {
_error: PhantomData<E>,
#[pin]
inner: F,
}
}
impl<F, E> WrapErrorFuture<F, E> {
pub(crate) fn new(inner: F) -> Self {
Self {
_error: PhantomData,
inner,
}
}
}
impl<F, E> Future for WrapErrorFuture<F, E>
where
F: Future<Output = Result<(), E>>,
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
type Output = Result<()>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.project();
let res = ready!(s.inner.poll(cx));
Poll::Ready(res.map_err(Error::handler))
}
}
pin_project! {
#[must_use]
#[project = HandlerCallParseRequestProject]
struct HandlerCallParseRequest<B, S>
where
B: Body,
{
#[pin]
parse_request: ParseRequest<B>,
service: S,
}
}
impl<B, S> Future for HandlerCallParseRequest<B, S>
where
B: Body,
B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
S: Service<Event>,
{
type Output = Result<S::Future>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.project();
let event = match ready!(s.parse_request.poll(cx)) {
Ok(e) => e,
Err(e) => return Poll::Ready(Err(e)),
};
let call = s.service.call(event);
Poll::Ready(Ok(call))
}
}
pin_project! {
#[must_use]
#[project = HandlerCallServiceCallProject]
struct HandlerCallServiceCall<F> {
#[pin]
inner: F,
}
}
impl<F> Future for HandlerCallServiceCall<F>
where
F: Future<Output = Result<(), Error>>,
{
type Output = Result<Response<String>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.project();
if let Err(e) = ready!(s.inner.poll(cx)) {
return Poll::Ready(Err(e));
}
let res = Response::builder()
.status(StatusCode::NO_CONTENT)
.body(String::new())
.map_err(Error::handler);
Poll::Ready(res)
}
}
pin_project! {
#[must_use]
#[project = HandlerCallInnerProject]
#[project_replace = HandlerCallInnerProjectReplace]
enum HandlerCallInner<B, S>
where
B: Body,
S: Service<Event>,
{
ParseRequest {
#[pin]
inner: HandlerCallParseRequest<B, S>,
},
ServiceCall {
#[pin]
inner: HandlerCallServiceCall<S::Future>,
},
}
}
impl<B, S> Future for HandlerCallInner<B, S>
where
B: Body,
B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
S: Service<Event, Response = (), Error = Error>,
{
type Output = Result<Response<String>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.as_mut().project();
let service_call = match s {
HandlerCallInnerProject::ParseRequest { inner } => match ready!(inner.poll(cx)) {
Ok(c) => c,
Err(e) => return Poll::Ready(Err(e)),
},
HandlerCallInnerProject::ServiceCall { inner } => return inner.poll(cx),
};
self.project_replace(HandlerCallInner::ServiceCall {
inner: HandlerCallServiceCall {
inner: service_call,
},
});
cx.waker().wake_by_ref();
Poll::Pending
}
}
pin_project! {
#[must_use]
#[project = HandlerCallProject]
pub struct HandlerCall<B, S>
where
B: Body,
S: Service<Event>,
{
#[pin]
inner: HandlerCallInner<B, S>,
}
}
impl<B, S> HandlerCall<B, S>
where
B: Body,
S: Service<Event>,
{
pub(super) fn new(parse_request: ParseRequest<B>, service: S) -> Self {
Self {
inner: HandlerCallInner::ParseRequest {
inner: HandlerCallParseRequest {
parse_request,
service,
},
},
}
}
}
impl<B, S> Future for HandlerCall<B, S>
where
B: Body,
B::Error: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
S: Service<Event, Response = (), Error = Error>,
{
type Output = Result<Response<String>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let s = self.project();
s.inner.poll(cx)
}
}