use axum::body::Body;
use axum::extract::Request;
use axum::{
extract::FromRequest,
handler::Handler,
response::{IntoResponse, Response},
};
use futures_util::future::{BoxFuture, FutureExt, Map};
use std::{future::Future, marker::PhantomData};
mod or;
pub use self::or::Or;
pub trait HandlerCallWithExtractors<T, S>: Sized {
type Future: Future<Output = Response> + Send + 'static;
fn call(self, extractors: T, state: S) -> <Self as HandlerCallWithExtractors<T, S>>::Future;
fn into_handler(self) -> IntoHandler<Self, T, S> {
IntoHandler {
handler: self,
_marker: PhantomData,
}
}
fn or<R, Rt>(self, rhs: R) -> Or<Self, R, T, Rt, S>
where
R: HandlerCallWithExtractors<Rt, S>,
{
Or {
lhs: self,
rhs,
_marker: PhantomData,
}
}
}
macro_rules! impl_handler_call_with {
( $($ty:ident),* $(,)? ) => {
#[allow(non_snake_case)]
impl<F, Fut, S, $($ty,)*> HandlerCallWithExtractors<($($ty,)*), S> for F
where
F: FnOnce($($ty,)*) -> Fut,
Fut: Future + Send + 'static,
Fut::Output: IntoResponse,
{
type Future = Map<Fut, fn(Fut::Output) -> Response>;
fn call(
self,
($($ty,)*): ($($ty,)*),
_state: S,
) -> <Self as HandlerCallWithExtractors<($($ty,)*), S>>::Future {
self($($ty,)*).map(IntoResponse::into_response)
}
}
};
}
impl_handler_call_with!();
impl_handler_call_with!(T1);
impl_handler_call_with!(T1, T2);
impl_handler_call_with!(T1, T2, T3);
impl_handler_call_with!(T1, T2, T3, T4);
impl_handler_call_with!(T1, T2, T3, T4, T5);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15);
impl_handler_call_with!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16);
#[allow(missing_debug_implementations)]
pub struct IntoHandler<H, T, S> {
handler: H,
_marker: PhantomData<fn() -> (T, S)>,
}
impl<H, T, S> Handler<T, S> for IntoHandler<H, T, S>
where
H: HandlerCallWithExtractors<T, S> + Clone + Send + Sync + 'static,
T: FromRequest<S> + Send + 'static,
T::Rejection: Send,
S: Send + Sync + 'static,
{
type Future = BoxFuture<'static, Response>;
fn call(self, req: Request, state: S) -> Self::Future {
let req = req.map(Body::new);
Box::pin(async move {
match T::from_request(req, &state).await {
Ok(t) => self.handler.call(t, state).await,
Err(rejection) => rejection.into_response(),
}
})
}
}
impl<H, T, S> Copy for IntoHandler<H, T, S> where H: Copy {}
impl<H, T, S> Clone for IntoHandler<H, T, S>
where
H: Clone,
{
fn clone(&self) -> Self {
Self {
handler: self.handler.clone(),
_marker: self._marker,
}
}
}