use std::sync::Arc;
use crate::{Flow, IntoResponse, Response};
pub trait Handler<I, S>: Sized {
type Output;
type Exception: IntoResponse;
type Future: Future<Output = Flow<Self::Output, Self::Exception>>;
fn handle(&self, input: I, state: S) -> Self::Future;
fn then<H>(self, handler: H) -> (Self, Arc<H>)
where
H: Handler<Self::Output, S>,
{
(self, Arc::new(handler))
}
}
pub trait Layer<H> {
type Handler;
fn wrap(self, handler: H) -> Self::Handler;
}
impl<F, Fut, I, S, O, E> Handler<I, S> for F
where
F: Fn(I, S) -> Fut,
Fut: Future<Output = Flow<O, E>>,
E: IntoResponse,
{
type Output = O;
type Exception = E;
type Future = Fut;
fn handle(&self, input: I, state: S) -> Self::Future {
self(input, state)
}
}
impl<H0, H1, I, S> Handler<I, S> for (H0, Arc<H1>)
where
H0: Handler<I, S>,
H0::Future: 'static,
H1: Handler<H0::Output, S> + 'static,
S: Clone + 'static,
{
type Output = H1::Output;
type Exception = Response;
type Future = impl Future<Output = Flow<Self::Output, Self::Exception>> + 'static;
fn handle(&self, input: I, state: S) -> Self::Future {
let future = self.0.handle(input, state.clone());
let handler = self.1.clone();
async move {
let output = future.await.map_exception(IntoResponse::into_response)?;
handler
.handle(output, state)
.await
.map_exception(IntoResponse::into_response)
}
}
}