Path: blob/main/crates/bevy_reflect/src/func/reflect_fn.rs
6599 views
use variadics_please::all_tuples;12use crate::{3func::{4args::{ArgCount, FromArg},5macros::count_tokens,6ArgList, FunctionError, FunctionResult, IntoReturn, ReflectFnMut,7},8Reflect, TypePath,9};1011/// A reflection-based version of the [`Fn`] trait.12///13/// This allows functions to be called dynamically through [reflection].14///15/// # Blanket Implementation16///17/// This trait has a blanket implementation that covers:18/// - Functions and methods defined with the `fn` keyword19/// - Anonymous functions20/// - Function pointers21/// - Closures that capture immutable references to their environment22/// - Closures that take ownership of captured variables23///24/// For each of the above cases, the function signature may only have up to 15 arguments,25/// not including an optional receiver argument (often `&self` or `&mut self`).26/// This optional receiver argument may be either a mutable or immutable reference to a type.27/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.28///29/// See the [module-level documentation] for more information on valid signatures.30///31/// To handle functions that capture mutable references to their environment,32/// see the [`ReflectFnMut`] trait instead.33///34/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].35/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].36///37/// # Example38///39/// ```40/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFn};41/// #42/// fn add(a: i32, b: i32) -> i32 {43/// a + b44/// }45///46/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);47///48/// let value = add.reflect_call(args).unwrap().unwrap_owned();49/// assert_eq!(value.try_take::<i32>().unwrap(), 100);50/// ```51///52/// # Trait Parameters53///54/// This trait has a `Marker` type parameter that is used to get around issues with55/// [unconstrained type parameters] when defining impls with generic arguments or return types.56/// This `Marker` can be any type, provided it doesn't conflict with other implementations.57///58/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.59/// For named functions and some closures, this will end up just being `'static`,60/// however, closures that borrow from their environment will have a lifetime bound to that environment.61///62/// [reflection]: crate63/// [module-level documentation]: crate::func64/// [derive macro]: derive@crate::Reflect65/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html66pub trait ReflectFn<'env, Marker>: ReflectFnMut<'env, Marker> {67/// Call the function with the given arguments and return the result.68fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;69}7071/// Helper macro for implementing [`ReflectFn`] on Rust functions.72///73/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):74/// - `Fn(arg0, arg1, ..., argN) -> R`75/// - `Fn(&Receiver, arg0, arg1, ..., argN) -> &R`76/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`77/// - `Fn(&mut Receiver, arg0, arg1, ..., argN) -> &R`78macro_rules! impl_reflect_fn {79($(($Arg:ident, $arg:ident)),*) => {80// === (...) -> ReturnType === //81impl<'env, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn($($Arg),*) -> [ReturnType]> for Function82where83$($Arg: FromArg,)*84// This clause allows us to convert `ReturnType` into `Return`85ReturnType: IntoReturn + Reflect,86Function: Fn($($Arg),*) -> ReturnType + 'env,87// This clause essentially asserts that `Arg::This` is the same type as `Arg`88Function: for<'a> Fn($($Arg::This<'a>),*) -> ReturnType + 'env,89{90#[expect(91clippy::allow_attributes,92reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."93)]94#[allow(95unused_mut,96reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."97)]98fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {99const COUNT: usize = count_tokens!($($Arg)*);100101if args.len() != COUNT {102return Err(FunctionError::ArgCountMismatch {103expected: ArgCount::new(COUNT).unwrap(),104received: args.len(),105});106}107108// Extract all arguments (in order)109$(let $arg = args.take::<$Arg>()?;)*110111Ok((self)($($arg,)*).into_return())112}113}114115// === (&self, ...) -> &ReturnType === //116impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function117where118Receiver: Reflect + TypePath,119$($Arg: FromArg,)*120ReturnType: Reflect,121// This clause allows us to convert `&ReturnType` into `Return`122for<'a> &'a ReturnType: IntoReturn,123Function: for<'a> Fn(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,124// This clause essentially asserts that `Arg::This` is the same type as `Arg`125Function: for<'a> Fn(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,126{127fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {128const COUNT: usize = count_tokens!(Receiver $($Arg)*);129130if args.len() != COUNT {131return Err(FunctionError::ArgCountMismatch {132expected: ArgCount::new(COUNT).unwrap(),133received: args.len(),134});135}136137// Extract all arguments (in order)138let receiver = args.take_ref::<Receiver>()?;139$(let $arg = args.take::<$Arg>()?;)*140141Ok((self)(receiver, $($arg,)*).into_return())142}143}144145// === (&mut self, ...) -> &mut ReturnType === //146impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function147where148Receiver: Reflect + TypePath,149$($Arg: FromArg,)*150ReturnType: Reflect,151// This clause allows us to convert `&mut ReturnType` into `Return`152for<'a> &'a mut ReturnType: IntoReturn,153Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,154// This clause essentially asserts that `Arg::This` is the same type as `Arg`155Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,156{157fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {158const COUNT: usize = count_tokens!(Receiver $($Arg)*);159160if args.len() != COUNT {161return Err(FunctionError::ArgCountMismatch {162expected: ArgCount::new(COUNT).unwrap(),163received: args.len(),164});165}166167// Extract all arguments (in order)168let receiver = args.take_mut::<Receiver>()?;169$(let $arg = args.take::<$Arg>()?;)*170171Ok((self)(receiver, $($arg,)*).into_return())172}173}174175// === (&mut self, ...) -> &ReturnType === //176impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFn<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function177where178Receiver: Reflect + TypePath,179$($Arg: FromArg,)*180ReturnType: Reflect,181// This clause allows us to convert `&ReturnType` into `Return`182for<'a> &'a ReturnType: IntoReturn,183Function: for<'a> Fn(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,184// This clause essentially asserts that `Arg::This` is the same type as `Arg`185Function: for<'a> Fn(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,186{187fn reflect_call<'a>(&self, mut args: ArgList<'a>) -> FunctionResult<'a> {188const COUNT: usize = count_tokens!(Receiver $($Arg)*);189190if args.len() != COUNT {191return Err(FunctionError::ArgCountMismatch {192expected: ArgCount::new(COUNT).unwrap(),193received: args.len(),194});195}196197// Extract all arguments (in order)198let receiver = args.take_mut::<Receiver>()?;199$(let $arg = args.take::<$Arg>()?;)*200201Ok((self)(receiver, $($arg,)*).into_return())202}203}204};205}206207all_tuples!(impl_reflect_fn, 0, 15, Arg, arg);208209210