use std::{future::Future, pin::Pin};
use crate::from_request::{FromRequest, IntoHandlerError};
use crate::{Error, HttpRequest, HttpResponse};
pub trait IntoHandler<Args> {
type Future: Future<Output = Result<HttpResponse, Error>>;
fn into_handler(self) -> Box<dyn Fn(HttpRequest) -> Self::Future + Send + Sync>;
}
pub struct HandlerFuture<F> {
inner: F,
}
impl<F> HandlerFuture<F> {
pub const fn new(future: F) -> Self {
Self { inner: future }
}
}
impl<F> Future for HandlerFuture<F>
where
F: Future<Output = Result<HttpResponse, Error>>,
{
type Output = Result<HttpResponse, Error>;
fn poll(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
let inner = unsafe { self.map_unchecked_mut(|s| &mut s.inner) };
inner.poll(cx)
}
}
#[cfg(feature = "actix")]
pub trait HandlerSend: Send {}
#[cfg(not(feature = "actix"))]
pub trait HandlerSend {}
#[cfg(feature = "actix")]
impl<T: Send> HandlerSend for T {}
#[cfg(not(feature = "actix"))]
impl<T> HandlerSend for T {}
macro_rules! impl_handler {
($T1:ident) => {
impl<F, Fut, $T1> IntoHandler<($T1,)> for F
where
F: Fn($T1) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<HttpResponse, Error>> + Send + 'static,
$T1: FromRequest + Send + 'static,
$T1::Error: Send + 'static,
$T1::Future: Send + 'static,
{
type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>;
fn into_handler(self) -> Box<dyn Fn(HttpRequest) -> Self::Future + Send + Sync> {
let handler = std::sync::Arc::new(self);
Box::new(move |req| {
let handler = handler.clone();
#[cfg(feature = "actix")]
{
let extracted = match $T1::from_request_sync(&req) {
Ok(value) => value,
Err(e) => return Box::pin(async move { Err(e.into_handler_error()) }),
};
Box::pin(async move {
handler(extracted).await
})
}
#[cfg(not(feature = "actix"))]
{
Box::pin(async move {
let extracted = match $T1::from_request_async(req).await {
Ok(value) => value,
Err(e) => return Err(e.into_handler_error()),
};
handler(extracted).await
})
}
})
}
}
};
($T1:ident, $($T:ident),+) => {
impl<F, Fut, $T1, $($T),+> IntoHandler<($T1, $($T),+)> for F
where
F: Fn($T1, $($T),+) -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<HttpResponse, Error>> + Send + 'static,
$T1: FromRequest + Send + 'static,
$T1::Error: Send + 'static,
$T1::Future: Send + 'static,
$(
$T: FromRequest + Send + 'static,
$T::Error: Send + 'static,
$T::Future: Send + 'static,
)+
{
type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>;
fn into_handler(self) -> Box<dyn Fn(HttpRequest) -> Self::Future + Send + Sync> {
let handler = std::sync::Arc::new(self);
Box::new(move |req| {
let handler = handler.clone();
#[cfg(feature = "actix")]
{
let param1 = match $T1::from_request_sync(&req) {
Ok(value) => value,
Err(e) => return Box::pin(async move { Err(e.into_handler_error()) }),
};
$(
let $T = match $T::from_request_sync(&req) {
Ok(value) => value,
Err(e) => return Box::pin(async move { Err(e.into_handler_error()) }),
};
)+
Box::pin(async move {
handler(param1, $($T),+).await
})
}
#[cfg(not(feature = "actix"))]
{
Box::pin(async move {
let param1 = match $T1::from_request_async(req.clone()).await {
Ok(value) => value,
Err(e) => return Err(e.into_handler_error()),
};
$(
let $T = match $T::from_request_async(req.clone()).await {
Ok(value) => value,
Err(e) => return Err(e.into_handler_error()),
};
)+
handler(param1, $($T),+).await
})
}
})
}
}
};
}
impl<F, Fut> IntoHandler<()> for F
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = Result<HttpResponse, Error>> + Send + 'static,
{
type Future = Pin<Box<dyn Future<Output = Result<HttpResponse, Error>> + Send>>;
fn into_handler(self) -> Box<dyn Fn(HttpRequest) -> Self::Future + Send + Sync> {
let handler = std::sync::Arc::new(self);
Box::new(move |_req| {
let handler = handler.clone();
Box::pin(async move { handler().await })
})
}
}
#[allow(non_snake_case, unused_attributes)]
mod handler_impls {
use super::{
Error, FromRequest, Future, HttpRequest, HttpResponse, IntoHandler, IntoHandlerError, Pin,
};
impl_handler!(T1); impl_handler!(T1, T2); impl_handler!(T1, T2, T3); impl_handler!(T1, T2, T3, T4); impl_handler!(T1, T2, T3, T4, T5); impl_handler!(T1, T2, T3, T4, T5, T6); impl_handler!(T1, T2, T3, T4, T5, T6, T7); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13); impl_handler!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14); impl_handler!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
); impl_handler!(
T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16
); }