Path: blob/main/crates/bevy_reflect/src/func/reflect_fn_mut.rs
6599 views
use variadics_please::all_tuples;12use crate::{3func::{4args::{ArgCount, FromArg},5macros::count_tokens,6ArgList, FunctionError, FunctionResult, IntoReturn,7},8Reflect, TypePath,9};1011/// A reflection-based version of the [`FnMut`] trait.12///13/// This allows functions to be called dynamically through [reflection].14///15/// This is a supertrait of [`ReflectFn`], and is used for functions that may mutate their environment,16/// such as closures that capture mutable references.17///18/// # Blanket Implementation19///20/// This trait has a blanket implementation that covers everything that [`ReflectFn`] does:21/// - Functions and methods defined with the `fn` keyword22/// - Anonymous functions23/// - Function pointers24/// - Closures that capture immutable references to their environment25/// - Closures that take ownership of captured variables26///27/// But also allows for:28/// - Closures that capture mutable references to their environment29///30/// For each of the above cases, the function signature may only have up to 15 arguments,31/// not including an optional receiver argument (often `&self` or `&mut self`).32/// This optional receiver argument may be either a mutable or immutable reference to a type.33/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.34///35/// See the [module-level documentation] for more information on valid signatures.36///37/// Arguments are expected to implement [`FromArg`], and the return type is expected to implement [`IntoReturn`].38/// Both of these traits are automatically implemented when using the `Reflect` [derive macro].39///40/// # Example41///42/// ```43/// # use bevy_reflect::func::{ArgList, FunctionInfo, ReflectFnMut};44/// #45/// let mut list: Vec<i32> = vec![1, 3];46///47/// // `insert` is a closure that captures a mutable reference to `list`48/// let mut insert = |index: usize, value: i32| {49/// list.insert(index, value);50/// };51///52/// let args = ArgList::new().with_owned(1_usize).with_owned(2_i32);53///54/// insert.reflect_call_mut(args).unwrap();55/// assert_eq!(list, vec![1, 2, 3]);56/// ```57///58/// # Trait Parameters59///60/// This trait has a `Marker` type parameter that is used to get around issues with61/// [unconstrained type parameters] when defining impls with generic arguments or return types.62/// This `Marker` can be any type, provided it doesn't conflict with other implementations.63///64/// Additionally, it has a lifetime parameter, `'env`, that is used to bound the lifetime of the function.65/// For named functions and some closures, this will end up just being `'static`,66/// however, closures that borrow from their environment will have a lifetime bound to that environment.67///68/// [reflection]: crate69/// [`ReflectFn`]: crate::func::ReflectFn70/// [module-level documentation]: crate::func71/// [derive macro]: derive@crate::Reflect72/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html73pub trait ReflectFnMut<'env, Marker> {74/// Call the function with the given arguments and return the result.75fn reflect_call_mut<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a>;76}7778/// Helper macro for implementing [`ReflectFnMut`] on Rust functions.79///80/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):81/// - `FnMut(arg0, arg1, ..., argN) -> R`82/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`83/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`84/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`85macro_rules! impl_reflect_fn_mut {86($(($Arg:ident, $arg:ident)),*) => {87// === (...) -> ReturnType === //88impl<'env, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn($($Arg),*) -> [ReturnType]> for Function89where90$($Arg: FromArg,)*91// This clause allows us to convert `ReturnType` into `Return`92ReturnType: IntoReturn + Reflect,93Function: FnMut($($Arg),*) -> ReturnType + 'env,94// This clause essentially asserts that `Arg::This` is the same type as `Arg`95Function: for<'a> FnMut($($Arg::This<'a>),*) -> ReturnType + 'env,96{97#[expect(98clippy::allow_attributes,99reason = "This lint is part of a macro, which may not always trigger the `unused_mut` lint."100)]101#[allow(102unused_mut,103reason = "Some invocations of this macro may trigger the `unused_mut` lint, where others won't."104)]105fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {106const COUNT: usize = count_tokens!($($Arg)*);107108if args.len() != COUNT {109return Err(FunctionError::ArgCountMismatch {110expected: ArgCount::new(COUNT).unwrap(),111received: args.len(),112});113}114115// Extract all arguments (in order)116$(let $arg = args.take::<$Arg>()?;)*117118Ok((self)($($arg,)*).into_return())119}120}121122// === (&self, ...) -> &ReturnType === //123impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&Receiver, $($Arg),*) -> &ReturnType> for Function124where125Receiver: Reflect + TypePath,126$($Arg: FromArg,)*127ReturnType: Reflect,128// This clause allows us to convert `&ReturnType` into `Return`129for<'a> &'a ReturnType: IntoReturn,130Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType + 'env,131// This clause essentially asserts that `Arg::This` is the same type as `Arg`132Function: for<'a> FnMut(&'a Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,133{134fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {135const COUNT: usize = count_tokens!(Receiver $($Arg)*);136137if args.len() != COUNT {138return Err(FunctionError::ArgCountMismatch {139expected: ArgCount::new(COUNT).unwrap(),140received: args.len(),141});142}143144// Extract all arguments (in order)145let receiver = args.take_ref::<Receiver>()?;146$(let $arg = args.take::<$Arg>()?;)*147148Ok((self)(receiver, $($arg,)*).into_return())149}150}151152// === (&mut self, ...) -> &mut ReturnType === //153impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function154where155Receiver: Reflect + TypePath,156$($Arg: FromArg,)*157ReturnType: Reflect,158// This clause allows us to convert `&mut ReturnType` into `Return`159for<'a> &'a mut ReturnType: IntoReturn,160Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType + 'env,161// This clause essentially asserts that `Arg::This` is the same type as `Arg`162Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a mut ReturnType + 'env,163{164fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {165const COUNT: usize = count_tokens!(Receiver $($Arg)*);166167if args.len() != COUNT {168return Err(FunctionError::ArgCountMismatch {169expected: ArgCount::new(COUNT).unwrap(),170received: args.len(),171});172}173174// Extract all arguments (in order)175let receiver = args.take_mut::<Receiver>()?;176$(let $arg = args.take::<$Arg>()?;)*177178Ok((self)(receiver, $($arg,)*).into_return())179}180}181182// === (&mut self, ...) -> &ReturnType === //183impl<'env, Receiver, $($Arg,)* ReturnType, Function> ReflectFnMut<'env, fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function184where185Receiver: Reflect + TypePath,186$($Arg: FromArg,)*187ReturnType: Reflect,188// This clause allows us to convert `&ReturnType` into `Return`189for<'a> &'a ReturnType: IntoReturn,190Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType + 'env,191// This clause essentially asserts that `Arg::This` is the same type as `Arg`192Function: for<'a> FnMut(&'a mut Receiver, $($Arg::This<'a>),*) -> &'a ReturnType + 'env,193{194fn reflect_call_mut<'a>(&mut self, mut args: ArgList<'a>) -> FunctionResult<'a> {195const COUNT: usize = count_tokens!(Receiver $($Arg)*);196197if args.len() != COUNT {198return Err(FunctionError::ArgCountMismatch {199expected: ArgCount::new(COUNT).unwrap(),200received: args.len(),201});202}203204// Extract all arguments (in order)205let receiver = args.take_mut::<Receiver>()?;206$(let $arg = args.take::<$Arg>()?;)*207208Ok((self)(receiver, $($arg,)*).into_return())209}210}211};212}213214all_tuples!(impl_reflect_fn_mut, 0, 15, Arg, arg);215216217