use std::future::Future;
use std::marker::PhantomData;
use std::pin::Pin;
use tower::util::BoxCloneSyncService;
use crate::error::ErrorRepr;
use crate::request::Request;
use crate::request::extractors::{FromRequest, FromRequestParts};
use crate::response::{Response, not_found_response};
use crate::{Error, Result};
#[diagnostic::on_unimplemented(
message = "`{Self}` is not a valid request handler",
label = "not a valid request handler",
note = "make sure the function is marked `async`",
note = "make sure all parameters implement `FromRequest` or `FromRequestParts`",
note = "make sure there is at most one parameter implementing `FromRequest`",
note = "make sure the function takes no more than 10 parameters"
)]
pub trait RequestHandler<T = ()> {
fn handle(&self, request: Request) -> impl Future<Output = Result<Response>> + Send;
}
pub(crate) trait BoxRequestHandler {
fn handle(
&self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + '_>>;
}
pub(crate) fn into_box_request_handler<T, H: RequestHandler<T> + Send + Sync>(
handler: H,
) -> impl BoxRequestHandler {
struct Inner<T, H>(H, PhantomData<fn() -> T>);
impl<T, H: RequestHandler<T> + Send + Sync> BoxRequestHandler for Inner<T, H> {
fn handle(
&self,
request: Request,
) -> Pin<Box<dyn Future<Output = Result<Response>> + Send + '_>> {
Box::pin(async move {
let response = self.0.handle(request).await;
match response {
Ok(response) => Ok(response),
Err(error) => match error.inner {
ErrorRepr::NotFound { message } => Ok(not_found_response(message)),
_ => Err(error),
},
}
})
}
}
Inner(handler, PhantomData)
}
macro_rules! impl_request_handler {
($($ty:ident),*) => {
impl<T, $($ty,)* R> RequestHandler<($($ty,)*)> for T
where
T: Fn($($ty,)*) -> R + Clone + Send + Sync + 'static,
$($ty: FromRequestParts + Send,)*
R: for<'a> Future<Output = Result<Response>> + Send,
{
#[allow(non_snake_case)]
async fn handle(&self, request: Request) -> Result<Response> {
#[allow(unused_variables, unused_mut)] let (mut parts, _body) = request.into_parts();
$(
let $ty = $ty::from_request_parts(&mut parts).await?;
)*
self($($ty,)*).await
}
}
};
}
macro_rules! impl_request_handler_from_request {
($($ty_lhs:ident,)* ($ty_from_request:ident) $(,$ty_rhs:ident)*) => {
impl<T, $($ty_lhs,)* $ty_from_request, $($ty_rhs,)* R> RequestHandler<($($ty_lhs,)* $ty_from_request, (), $($ty_rhs,)*)> for T
where
T: Fn($($ty_lhs,)* $ty_from_request, $($ty_rhs),*) -> R + Clone + Send + Sync + 'static,
$($ty_lhs: FromRequestParts + Send,)*
$ty_from_request: FromRequest + Send,
$($ty_rhs: FromRequestParts + Send,)*
R: for<'a> Future<Output = Result<Response>> + Send,
{
#[expect(non_snake_case)]
async fn handle(&self, request: Request) -> Result<Response> {
#[allow(unused_mut)] let (mut parts, body) = request.into_parts();
$(
let $ty_lhs = $ty_lhs::from_request_parts(&mut parts).await?;
)*
$(
let $ty_rhs = $ty_rhs::from_request_parts(&mut parts).await?;
)*
let request = Request::from_parts(parts, body);
let $ty_from_request = $ty_from_request::from_request(request).await?;
self($($ty_lhs,)* $ty_from_request, $($ty_rhs),*).await
}
}
};
}
impl_request_handler!();
impl_request_handler!(P1);
impl_request_handler!(P1, P2);
impl_request_handler!(P1, P2, P3);
impl_request_handler!(P1, P2, P3, P4);
impl_request_handler!(P1, P2, P3, P4, P5);
impl_request_handler!(P1, P2, P3, P4, P5, P6);
impl_request_handler!(P1, P2, P3, P4, P5, P6, P7);
impl_request_handler!(P1, P2, P3, P4, P5, P6, P7, P8);
impl_request_handler!(P1, P2, P3, P4, P5, P6, P7, P8, P9);
impl_request_handler!(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10);
impl_request_handler_from_request!((P1));
impl_request_handler_from_request!((P1), P2);
impl_request_handler_from_request!(P1, (P2));
impl_request_handler_from_request!((P1), P2, P3);
impl_request_handler_from_request!(P1, (P2), P3);
impl_request_handler_from_request!(P1, P2, (P3));
impl_request_handler_from_request!((P1), P2, P3, P4);
impl_request_handler_from_request!(P1, (P2), P3, P4);
impl_request_handler_from_request!(P1, P2, (P3), P4);
impl_request_handler_from_request!(P1, P2, P3, (P4));
impl_request_handler_from_request!((P1), P2, P3, P4, P5);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5));
impl_request_handler_from_request!((P1), P2, P3, P4, P5, P6);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5, P6);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5, P6);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5, P6);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5), P6);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, (P6));
impl_request_handler_from_request!((P1), P2, P3, P4, P5, P6, P7);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5, P6, P7);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5, P6, P7);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5, P6, P7);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5), P6, P7);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, (P6), P7);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, (P7));
impl_request_handler_from_request!((P1), P2, P3, P4, P5, P6, P7, P8);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5, P6, P7, P8);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5, P6, P7, P8);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5, P6, P7, P8);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5), P6, P7, P8);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, (P6), P7, P8);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, (P7), P8);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, (P8));
impl_request_handler_from_request!((P1), P2, P3, P4, P5, P6, P7, P8, P9);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5, P6, P7, P8, P9);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5, P6, P7, P8, P9);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5, P6, P7, P8, P9);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5), P6, P7, P8, P9);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, (P6), P7, P8, P9);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, (P7), P8, P9);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, (P8), P9);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, P8, (P9));
impl_request_handler_from_request!((P1), P2, P3, P4, P5, P6, P7, P8, P9, P10);
impl_request_handler_from_request!(P1, (P2), P3, P4, P5, P6, P7, P8, P9, P10);
impl_request_handler_from_request!(P1, P2, (P3), P4, P5, P6, P7, P8, P9, P10);
impl_request_handler_from_request!(P1, P2, P3, (P4), P5, P6, P7, P8, P9, P10);
impl_request_handler_from_request!(P1, P2, P3, P4, (P5), P6, P7, P8, P9, P10);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, (P6), P7, P8, P9, P10);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, (P7), P8, P9, P10);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, (P8), P9, P10);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, P8, (P9), P10);
impl_request_handler_from_request!(P1, P2, P3, P4, P5, P6, P7, P8, P9, (P10));
pub type BoxedHandler = BoxCloneSyncService<Request, Response, Error>;