rquickjs_core/value/function/
into_func.rsuse super::{FromParams, IntoJsFunc, ParamRequirement, Params};
use crate::{
    function::types::{MutFn, OnceFn},
    result::{BorrowError, Error},
    IntoJs, Result, Value,
};
#[cfg(feature = "futures")]
use crate::{function::types::Async, promise::Promised};
#[cfg(feature = "futures")]
use std::future::Future;
macro_rules! impl_to_js_function {
    ($($t:ident),*$(,)?) => {
        impl<'js, R, Fun $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for Fun
        where
            Fun: Fn($($t),*) -> R + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let r = (self)($($t),*);
                r.into_js(&ctx)
            }
        }
        #[cfg(feature = "futures")]
        impl<'js, R, Fun, Fut $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for Async<Fun>
        where
            Fun: Fn($($t),*) -> Fut + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            Fut: Future<Output = R> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let fut = (self.0)($($t),*);
                Promised(fut).into_js(&ctx)
            }
        }
        impl<'js, R, Fun $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for MutFn<Fun>
        where
            Fun: FnMut($($t),*) -> R + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let mut lock = self.0.try_borrow_mut().map_err(|_| Error::FunctionBorrow(BorrowError::AlreadyBorrowed))?;
                let r = (lock)($($t),*);
                r.into_js(&ctx)
            }
        }
        #[cfg(feature = "futures")]
        impl<'js, R, Fun, Fut $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for Async<MutFn<Fun>>
        where
            Fun: FnMut($($t),*) -> Fut + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            Fut: Future<Output = R> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let mut lock = self.0.0.try_borrow_mut().map_err(|_| Error::FunctionBorrow(BorrowError::AlreadyBorrowed))?;
                let fut = (lock)($($t),*);
                Promised(fut).into_js(&ctx)
            }
        }
        impl<'js, R, Fun $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for OnceFn<Fun>
        where
            Fun: FnOnce($($t),*) -> R + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let lock = self.0.take().ok_or(Error::FunctionBorrow(BorrowError::AlreadyUsed))?;
                let r = (lock)($($t),*);
                r.into_js(&ctx)
            }
        }
        #[cfg(feature = "futures")]
        impl<'js, R, Fun, Fut $(,$t)*> IntoJsFunc<'js, ($($t,)*)> for Async<OnceFn<Fun>>
        where
            Fun: FnOnce($($t),*) -> Fut + 'js,
            ($($t,)*): FromParams<'js> + 'js,
            Fut: Future<Output = R> + 'js,
            R: IntoJs<'js> + 'js,
        {
            fn param_requirements() -> ParamRequirement {
                <($($t,)*)>::param_requirements()
            }
            #[allow(non_snake_case)]
            fn call(&self, params: Params<'_, 'js>) -> Result<Value<'js>> {
                let ctx = params.ctx().clone();
                let ($($t,)*) = <($($t,)*)>::from_params(&mut params.access())?;
                let lock = self.0.0.take().ok_or(Error::FunctionBorrow(BorrowError::AlreadyUsed))?;
                let fut = (lock)($($t),*);
                Promised(fut).into_js(&ctx)
            }
        }
    };
}
impl_to_js_function!();
impl_to_js_function!(A);
impl_to_js_function!(A, B);
impl_to_js_function!(A, B, C);
impl_to_js_function!(A, B, C, D);
impl_to_js_function!(A, B, C, D, E);
impl_to_js_function!(A, B, C, D, E, F);
impl_to_js_function!(A, B, C, D, E, F, G);
impl_to_js_function!(A, B, C, D, E, F, G, H);