use std::{
convert::Infallible,
future::Future,
marker::PhantomData,
task::{Context, Poll},
};
use futures_util::{future::Map, FutureExt};
use tower::Service;
use super::OperationShape;
pub trait Handler<Op, Exts>
where
Op: OperationShape,
{
type Future: Future<Output = Result<Op::Output, Op::Error>>;
fn call(&mut self, input: Op::Input, exts: Exts) -> Self::Future;
}
trait IntoResult<Ok, Error> {
fn into_result(self) -> Result<Ok, Error>;
}
impl<Ok, Error> IntoResult<Ok, Error> for Result<Ok, Error> {
fn into_result(self) -> Result<Ok, Error> {
self
}
}
impl<Ok> IntoResult<Ok, Infallible> for Ok {
fn into_result(self) -> Result<Ok, Infallible> {
Ok(self)
}
}
impl<Op, F, Fut> Handler<Op, ()> for F
where
Op: OperationShape,
F: Fn(Op::Input) -> Fut,
Fut: Future,
Fut::Output: IntoResult<Op::Output, Op::Error>,
{
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
fn call(&mut self, input: Op::Input, _exts: ()) -> Self::Future {
(self)(input).map(IntoResult::into_result)
}
}
macro_rules! impl_handler {
($($var:ident),+) => (
impl<Op, F, Fut, $($var,)*> Handler<Op, ($($var,)*)> for F
where
Op: OperationShape,
F: Fn(Op::Input, $($var,)*) -> Fut,
Fut: Future,
Fut::Output: IntoResult<Op::Output, Op::Error>,
{
type Future = Map<Fut, fn(Fut::Output) -> Result<Op::Output, Op::Error>>;
fn call(&mut self, input: Op::Input, exts: ($($var,)*)) -> Self::Future {
#[allow(non_snake_case)]
let ($($var,)*) = exts;
(self)(input, $($var,)*).map(IntoResult::into_result)
}
}
)
}
impl_handler!(Exts0);
impl_handler!(Exts0, Exts1);
impl_handler!(Exts0, Exts1, Exts2);
impl_handler!(Exts0, Exts1, Exts2, Exts3);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7);
impl_handler!(Exts0, Exts1, Exts2, Exts3, Exts4, Exts5, Exts6, Exts7, Exts8);
pub trait HandlerExt<Op, Exts>: Handler<Op, Exts>
where
Op: OperationShape,
{
fn into_service(self) -> IntoService<Op, Self>
where
Self: Sized,
{
IntoService {
handler: self,
_operation: PhantomData,
}
}
}
impl<Op, Exts, H> HandlerExt<Op, Exts> for H
where
Op: OperationShape,
H: Handler<Op, Exts>,
{
}
pub struct IntoService<Op, H> {
pub(crate) handler: H,
pub(crate) _operation: PhantomData<Op>,
}
impl<Op, H> Clone for IntoService<Op, H>
where
H: Clone,
{
fn clone(&self) -> Self {
Self {
handler: self.handler.clone(),
_operation: PhantomData,
}
}
}
impl<Op, Exts, H> Service<(Op::Input, Exts)> for IntoService<Op, H>
where
Op: OperationShape,
H: Handler<Op, Exts>,
{
type Response = Op::Output;
type Error = Op::Error;
type Future = H::Future;
fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, (input, exts): (Op::Input, Exts)) -> Self::Future {
self.handler.call(input, exts)
}
}