#![allow(non_snake_case)]
use core::{convert::Infallible, marker::PhantomData};
use super::{FromRequest, Responder};
use xitca_service::{FnService, Service, fn_build};
pub fn handler_sync_service<Arg, F, T>(func: F) -> FnService<impl AsyncFn(Arg) -> FnServiceOutput<F, T>>
where
F: Closure<T> + Send + Clone,
{
fn_build(async move |_| {
Ok(HandlerServiceSync {
func: func.clone(),
_p: PhantomData,
})
})
}
type FnServiceOutput<F, T> = Result<HandlerServiceSync<F, T>, Infallible>;
pub struct HandlerServiceSync<F, T> {
func: F,
_p: PhantomData<T>,
}
impl<F, Req, T, O> Service<Req> for HandlerServiceSync<F, T>
where
T: FromRequest<'static, Req>,
F: Closure<T> + Send + Clone + 'static,
F: for<'a> Closure<T::Type<'a>, Output = O>,
O: Responder<Req> + Send + 'static,
for<'a> T::Type<'a>: Send + 'static,
T::Error: From<O::Error>,
{
type Response = O::Response;
type Error = T::Error;
async fn call(&self, req: Req) -> Result<Self::Response, Self::Error> {
let extract = T::Type::<'_>::from_request(&req).await?;
let func = self.func.clone();
let res = tokio::task::spawn_blocking(move || func.call(extract)).await.unwrap();
res.respond(req).await.map_err(Into::into)
}
}
#[doc(hidden)]
pub trait Closure<Arg> {
type Output;
fn call(&self, arg: Arg) -> Self::Output;
}
macro_rules! closure_impl {
($($arg: ident),*) => {
impl<Func, O, $($arg,)*> Closure<($($arg,)*)> for Func
where
Func: Fn($($arg),*) -> O,
{
type Output = O;
#[inline]
fn call(&self, ($($arg,)*): ($($arg,)*)) -> Self::Output {
self($($arg,)*)
}
}
}
}
closure_impl! {}
closure_impl! { A }
closure_impl! { A, B }
closure_impl! { A, B, C }
closure_impl! { A, B, C, D }
closure_impl! { A, B, C, D, E }
closure_impl! { A, B, C, D, E, F }
closure_impl! { A, B, C, D, E, F, G }
closure_impl! { A, B, C, D, E, F, G, H }
closure_impl! { A, B, C, D, E, F, G, H, I }