use std::{future::Future, pin::Pin, sync::Arc};
use crate::callable::{supports::SupportsAsync, CallableParam};
pub type BoxedCallable<Ctx, Ret, Err> =
Box<dyn Fn(Ctx) -> Pin<Box<dyn Future<Output = Result<Ret, Err>> + Send + Sync>> + Send + Sync>;
pub trait IntoCallable<Ctx, Params, Ret, Err, Init: Send, const IS_ASYNC: bool>:
Send + Sync + Copy + 'static
{
fn into_callable(self, init: Init) -> BoxedCallable<Ctx, Ret, Err>;
}
macro_rules! impl_into_callable {
($($members:ident),*) => {
#[allow(unused_parens)]
impl<
Ctx,
Ret,
Err,
Init,
$($members),*,
F
> IntoCallable<Ctx, ($($members,)*), Ret, Err, Init, false> for F
where
F: (Fn($($members),*) -> Ret) + Copy + Send + Sync + 'static,
$($members: CallableParam<Ctx, Init> + Send + Sync),*,
$($members::Error: Send + Sync),*,
$(Err: From<$members::Error>),*,
Ret: serde::Serialize,
Init: Send + Sync + 'static,
Ctx: Send + Sync + 'static,
{
#[allow(non_snake_case)]
fn into_callable(self, init: Init) -> BoxedCallable<Ctx, Ret, Err> {
let init = Arc::new(init);
Box::new(move |mut ctx| {
let init = init.clone();
Box::pin(async move {
let ($($members),*) = ($($members::extract(&mut ctx, &init).await?),*);
Ok(self($($members),*))
})
})
}
}
#[allow(unused_parens)]
impl<
Ctx,
Ret,
Err,
Init,
$($members),*,
F,
Fut
> IntoCallable<Ctx, ($($members,)*), Ret, Err, Init, true> for F
where
F: (Fn($($members),*) -> Fut) + Copy + Send + Sync + 'static,
$($members: CallableParam<Ctx, Init> + SupportsAsync),*,
$($members::Error: Send + Sync),*,
$(Err: From<$members::Error>),*,
Ret: serde::Serialize,
Init: Send + Sync + 'static,
Ctx: Send + Sync + 'static,
Fut: Future<Output = Ret> + Send + Sync + 'static
{
#[allow(non_snake_case)]
fn into_callable(self, init: Init) -> BoxedCallable<Ctx, Ret, Err> {
let init = Arc::new(init);
Box::new(move |mut ctx| {
let init = init.clone();
Box::pin(async move {
let ($($members),*) = ($($members::extract(&mut ctx, &init).await?),*);
Ok(self($($members),*).await)
})
})
}
}
}
}
impl<Ctx, Ret, Err, Init, F> IntoCallable<Ctx, (), Ret, Err, Init, false> for F
where
F: (Fn() -> Ret) + Copy + Send + Sync + 'static,
Init: Send + Sync + 'static,
Ctx: 'static,
{
fn into_callable(self, _: Init) -> BoxedCallable<Ctx, Ret, Err> {
Box::new(move |_| Box::pin(async move { Ok(self()) }))
}
}
impl<Ctx, Ret, Err, Init, F, Fut> IntoCallable<Ctx, (), Ret, Err, Init, true> for F
where
F: (Fn() -> Fut) + Copy + Send + Sync + 'static,
Init: Send + Sync + 'static,
Ctx: 'static,
Fut: Future<Output = Ret> + Send + Sync + 'static,
{
fn into_callable(self, _: Init) -> BoxedCallable<Ctx, Ret, Err> {
Box::new(move |_| Box::pin(async move { Ok(self().await) }))
}
}
impl_into_callable!(T1);
impl_into_callable!(T1, T2);
impl_into_callable!(T1, T2, T3);
impl_into_callable!(T1, T2, T3, T4);
impl_into_callable!(T1, T2, T3, T4, T5);
impl_into_callable!(T1, T2, T3, T4, T5, T6);
impl_into_callable!(T1, T2, T3, T4, T5, T6, T7);
impl_into_callable!(T1, T2, T3, T4, T5, T6, T7, T8);