use crate::{
all_the_tuples,
extract::{Exclusive, FromContext, FromContextOnce},
BoxError, BoxFuture,
};
use std::{future::Future, marker::PhantomData, pin::Pin};
pub type HandlerResult = Result<(), BoxError>;
pub trait IntoHandlerResult {
fn into_handler_result(self) -> HandlerResult;
}
impl IntoHandlerResult for () {
fn into_handler_result(self) -> HandlerResult {
Ok(())
}
}
impl<E> IntoHandlerResult for Result<(), E>
where
E: Into<BoxError>,
{
fn into_handler_result(self) -> HandlerResult {
match self {
Ok(()) => Ok(()),
Err(err) => Err(err.into()),
}
}
}
#[derive(thiserror::Error, Debug)]
#[error("Extraction error: {0}")]
pub struct ExtractionError(pub Box<dyn std::error::Error>);
pub trait Handler<C> {
type Output;
type Future<'h>: Future<Output = Result<Self::Output, ExtractionError>>
where
Self: 'h,
C: 'h;
#[must_use]
fn call<'h>(&'h self, context: C) -> Self::Future<'h>
where
C: 'h;
}
pub struct HandlerFunction<F, I> {
function: F,
_arguments: PhantomData<I>,
}
impl<F: Clone, I> Clone for HandlerFunction<F, I> {
fn clone(&self) -> Self {
Self {
function: self.function.clone(),
_arguments: PhantomData,
}
}
}
impl<F, I> HandlerFunction<F, I> {
fn new(function: F) -> Self {
Self {
function,
_arguments: PhantomData,
}
}
}
impl<C, F, Fut> Handler<C> for HandlerFunction<F, ()>
where
F: Fn() -> Fut,
Fut: Future,
{
type Output = Fut::Output;
type Future<'h>
= BoxFuture<'h, Result<Self::Output, ExtractionError>>
where
Self: 'h,
C: 'h;
fn call<'h>(&'h self, _: C) -> Self::Future<'h>
where
C: 'h,
{
Box::pin(async move { Ok((self.function)().await) })
}
}
macro_rules! impl_handler_function {
(
$first:ident $(,$ty:ident)*
) => {
#[allow(non_snake_case)]
impl<C, F, Fut, M, $first, $($ty,)* > Handler<C> for
HandlerFunction<F, (M, $first, $($ty,)*)>
where
Fut: Future,
F: Fn($first, $($ty,)* ) -> Fut,
$first: FromContextOnce<C, M>,
$($ty: FromContext<C>,)*
{
type Output = <Fut as Future>::Output;
type Future<'h> = Pin<Box<dyn Future<Output = Result<Self::Output, ExtractionError>> + 'h>>
where Self: 'h, C: 'h;
fn call<'h>(&'h self, context: C) -> Self::Future<'h>
where
C: 'h,
{
#[allow(unused_mut)]
async fn extract<'c, C, M, $first, $($ty,)*>(context: &C) ->
Result<($first, $($ty,)*), ExtractionError>
where
$first: FromContextOnce<C, M>,
$($ty: FromContext<C>),*
{
let exclusive_context = Exclusive::new(context);
Ok((
$first::from_context_once(exclusive_context)
.await
.map_err(|e| ExtractionError(e.into()))?,
$($ty::from_context(context).map_err(|e| ExtractionError(e.into()))?,)*
))
}
Box::pin(async move {
let ($first, $($ty,)*) = extract::<C, M, $first, $($ty,)*>(&context).await?;
Ok((self.function)($first, $($ty,)*).await)
})
}
}
}
}
all_the_tuples!(impl_handler_function);
mod private {
pub enum HandlerIntoHandlerArgs {}
}
pub trait IntoHandler<C, I> {
type Output;
type Handler: Handler<C, Output = Self::Output>;
fn into_handler(self) -> Self::Handler;
}
impl<C, H> IntoHandler<C, private::HandlerIntoHandlerArgs> for H
where
H: Handler<C>,
{
type Output = H::Output;
type Handler = Self;
fn into_handler(self) -> Self::Handler {
self
}
}
impl<C, F, Fut> IntoHandler<C, ()> for F
where
F: Fn() -> Fut,
Fut: Future,
{
type Output = Fut::Output;
type Handler = HandlerFunction<F, ()>;
fn into_handler(self) -> Self::Handler {
HandlerFunction::new(self)
}
}
macro_rules! impl_into_handler {
(
$first:ident $(,$ty:ident)*
) => {
#[allow(non_snake_case)]
impl<C, F, Fut, M, $first, $($ty,)*> IntoHandler<C, (M, $first, $($ty,)*)> for F
where
Fut: Future,
F: Fn($first, $($ty,)* ) -> Fut,
$first: FromContextOnce<C, M>,
$($ty: FromContext<C>,)*
{
type Output = Fut::Output;
type Handler = HandlerFunction<F, (M, $first, $($ty,)*)>;
fn into_handler(self) -> Self::Handler {
HandlerFunction::new(self)
}
}
}
}
all_the_tuples!(impl_into_handler);