use variadics_please::all_tuples;
use crate::{
func::{
args::{ArgCount, FromArg},
macros::count_tokens,
ArgList, FunctionError, FunctionResult, IntoReturn, ReflectFnMut,
},
Reflect, TypePath,
};
pub trait ReflectFn<'env, Marker>: ReflectFnMut<'env, Marker> {
fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
}
macro_rules! impl_reflect_fn {
($(($Arg:ident, $arg:ident)),*) => {
impl<'env, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn($($Arg),*) -> [ReturnType]> for Function
where
$($Arg: FromArg,)*
ReturnType: IntoReturn + Reflect,
Function: Fn($($Arg),*) -> ReturnType + 'env,
Function: for<'a> Fn($($Arg::This<'a>),*) -> ReturnType + 'env,
{
#[expect(
clippy::allow_attributes,
reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."
)]
#[allow(
unused_mut,
reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."
)]
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!($($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)($($arg,)*).into_return())
}
}
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,
Function: for<'a> Fn(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
let receiver = args.take_ref::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
for<'a> &'a mut ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function
where
Receiver: Reflect + TypePath,
$($Arg: FromArg,)*
ReturnType: Reflect,
for<'a> &'a ReturnType: IntoReturn,
Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,
Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,
{
fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {
const COUNT: usize = count_tokens!(Receiver $($Arg)*);
if args.len() != COUNT {
return Err(FunctionError::ArgCountMismatch {
expected: ArgCount::new(COUNT).unwrap(),
received: args.len(),
});
}
let receiver = args.take_mut::<Receiver>()?;
$(let $arg = args.take::<$Arg>()?;)*
Ok((self)(receiver, $($arg,)*).into_return())
}
}
};
}
all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);