Path: blob/main/crates/bevy_reflect/src/func/dynamic_function_mut.rs
6599 views
use alloc::{borrow::Cow, boxed::Box};1use bevy_platform::sync::Arc;2use core::fmt::{Debug, Formatter};34use crate::func::{5args::{ArgCount, ArgList},6dynamic_function_internal::DynamicFunctionInternal,7DynamicFunction, FunctionInfo, FunctionOverloadError, FunctionResult, IntoFunctionMut,8};910/// A [`Box`] containing a callback to a reflected function.11type BoxFnMut<'env> = Box<dyn for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>;1213/// A dynamic representation of a function.14///15/// This type can be used to represent any callable that satisfies [`FnMut`]16/// (or the reflection-based equivalent, [`ReflectFnMut`]).17/// That is, any function or closure.18///19/// For functions that do not need to capture their environment mutably,20/// it's recommended to use [`DynamicFunction`] instead.21///22/// This type can be seen as a superset of [`DynamicFunction`].23///24/// See the [module-level documentation] for more information.25///26/// You will generally not need to construct this manually.27/// Instead, many functions and closures can be automatically converted using the [`IntoFunctionMut`] trait.28///29/// # Example30///31/// Most of the time, a [`DynamicFunctionMut`] can be created using the [`IntoFunctionMut`] trait:32///33/// ```34/// # use bevy_reflect::func::{ArgList, DynamicFunctionMut, FunctionInfo, IntoFunctionMut};35/// #36/// let mut list: Vec<i32> = vec![1, 2, 3];37///38/// // `replace` is a closure that captures a mutable reference to `list`39/// let mut replace = |index: usize, value: i32| -> i32 {40/// let old_value = list[index];41/// list[index] = value;42/// old_value43/// };44///45/// // Since this closure mutably borrows data, we can't convert it into a regular `DynamicFunction`,46/// // as doing so would result in a compile-time error:47/// // let mut func: DynamicFunction = replace.into_function();48///49/// // Instead, we convert it into a `DynamicFunctionMut` using `IntoFunctionMut::into_function_mut`:50/// let mut func: DynamicFunctionMut = replace.into_function_mut();51///52/// // Dynamically call it:53/// let args = ArgList::default().with_owned(1_usize).with_owned(-2_i32);54/// let value = func.call(args).unwrap().unwrap_owned();55///56/// // Check the result:57/// assert_eq!(value.try_take::<i32>().unwrap(), 2);58///59/// // Note that `func` still has a reference to `list`,60/// // so we need to drop it before we can access `list` again.61/// // Alternatively, we could have invoked `func` with62/// // `DynamicFunctionMut::call_once` to immediately consume it.63/// drop(func);64/// assert_eq!(list, vec![1, -2, 3]);65/// ```66///67/// [`ReflectFnMut`]: crate::func::ReflectFnMut68/// [module-level documentation]: crate::func69pub struct DynamicFunctionMut<'env> {70internal: DynamicFunctionInternal<BoxFnMut<'env>>,71}7273impl<'env> DynamicFunctionMut<'env> {74/// Create a new [`DynamicFunctionMut`].75///76/// The given function can be used to call out to any other callable,77/// including functions, closures, or methods.78///79/// It's important that the function signature matches the provided [`FunctionInfo`].80/// as this will be used to validate arguments when [calling] the function.81/// This is also required in order for [function overloading] to work correctly.82///83/// # Panics84///85/// This function may panic for any of the following reasons:86/// - No [`SignatureInfo`] is provided.87/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].88/// - The conversion to [`FunctionInfo`] fails.89///90/// [calling]: crate::func::dynamic_function_mut::DynamicFunctionMut::call91/// [`SignatureInfo`]: crate::func::SignatureInfo92/// [function overloading]: Self::with_overload93pub fn new<F: for<'a> FnMut(ArgList<'a>) -> FunctionResult<'a> + 'env>(94func: F,95info: impl TryInto<FunctionInfo, Error: Debug>,96) -> Self {97Self {98internal: DynamicFunctionInternal::new(Box::new(func), info.try_into().unwrap()),99}100}101102/// Set the name of the function.103///104/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],105/// the default name will always be the full path to the function as returned by [`core::any::type_name`],106/// unless the function is a closure, anonymous function, or function pointer,107/// in which case the name will be `None`.108///109/// [`DynamicFunctionMuts`]: DynamicFunctionMut110pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {111self.internal = self.internal.with_name(name);112self113}114115/// Add an overload to this function.116///117/// Overloads allow a single [`DynamicFunctionMut`] to represent multiple functions of different signatures.118///119/// This can be used to handle multiple monomorphizations of a generic function120/// or to allow functions with a variable number of arguments.121///122/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.123/// For example, if the existing function had the signature `(i32, i32) -> i32`,124/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,125/// the one from `F` would replace the one from the existing function.126///127/// Overloaded functions retain the [name] of the original function.128///129/// Note that it may be impossible to overload closures that mutably borrow from their environment130/// due to Rust's borrowing rules.131/// However, it's still possible to overload functions that do not capture their environment mutably,132/// or those that maintain mutually exclusive mutable references to their environment.133///134/// # Panics135///136/// Panics if the function, `F`, contains a signature already found in this function.137///138/// For a non-panicking version, see [`try_with_overload`].139///140/// # Example141///142/// ```143/// # use bevy_reflect::func::IntoFunctionMut;144/// let mut total_i32 = 0;145/// let mut add_i32 = |a: i32| total_i32 += a;146///147/// let mut total_f32 = 0.0;148/// let mut add_f32 = |a: f32| total_f32 += a;149///150/// // Currently, the only generic type `func` supports is `i32`.151/// let mut func = add_i32.into_function_mut();152///153/// // However, we can add an overload to handle `f32` as well:154/// func = func.with_overload(add_f32);155///156/// // Test `i32`:157/// let args = bevy_reflect::func::ArgList::new().with_owned(123_i32);158/// func.call(args).unwrap();159///160/// // Test `f32`:161/// let args = bevy_reflect::func::ArgList::new().with_owned(1.23_f32);162/// func.call(args).unwrap();163///164/// drop(func);165/// assert_eq!(total_i32, 123);166/// assert_eq!(total_f32, 1.23);167/// ```168///169/// [argument signature]: crate::func::signature::ArgumentSignature170/// [name]: Self::name171/// [`try_with_overload`]: Self::try_with_overload172pub fn with_overload<'a, F: IntoFunctionMut<'a, Marker>, Marker>(173self,174function: F,175) -> DynamicFunctionMut<'a>176where177'env: 'a,178{179self.try_with_overload(function).unwrap_or_else(|(_, err)| {180panic!("{}", err);181})182}183184/// Attempt to add an overload to this function.185///186/// If the function, `F`, contains a signature already found in this function,187/// an error will be returned along with the original function.188///189/// For a panicking version, see [`with_overload`].190///191/// [`with_overload`]: Self::with_overload192pub fn try_with_overload<F: IntoFunctionMut<'env, Marker>, Marker>(193mut self,194function: F,195) -> Result<Self, (Box<Self>, FunctionOverloadError)> {196let function = function.into_function_mut();197198match self.internal.merge(function.internal) {199Ok(_) => Ok(self),200Err(err) => Err((Box::new(self), err)),201}202}203204/// Call the function with the given arguments.205///206/// Variables that are captured mutably by this function207/// won't be usable until this function is dropped.208/// Consider using [`call_once`] if you want to consume the function209/// immediately after calling it.210///211/// # Example212///213/// ```214/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};215/// let mut total = 0;216/// let add = |a: i32, b: i32| -> i32 {217/// total = a + b;218/// total219/// };220///221/// let mut func = add.into_function_mut().with_name("add");222/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);223/// let result = func.call(args).unwrap().unwrap_owned();224/// assert_eq!(result.try_take::<i32>().unwrap(), 100);225/// ```226///227/// # Errors228///229/// This method will return an error if the number of arguments provided does not match230/// the number of arguments expected by the function's [`FunctionInfo`].231///232/// The function itself may also return any errors it needs to.233///234/// [`call_once`]: DynamicFunctionMut::call_once235pub fn call<'a>(&mut self, args: ArgList<'a>) -> FunctionResult<'a> {236self.internal.validate_args(&args)?;237let func = self.internal.get_mut(&args)?;238func(args)239}240241/// Call the function with the given arguments and consume it.242///243/// This is useful for functions that capture their environment mutably244/// because otherwise any captured variables would still be borrowed by it.245///246/// # Example247///248/// ```249/// # use bevy_reflect::func::{IntoFunctionMut, ArgList};250/// let mut count = 0;251/// let increment = |amount: i32| count += amount;252///253/// let increment_function = increment.into_function_mut();254/// let args = ArgList::new().with_owned(5_i32);255///256/// // We need to drop `increment_function` here so that we257/// // can regain access to `count`.258/// // `call_once` does this automatically for us.259/// increment_function.call_once(args).unwrap();260/// assert_eq!(count, 5);261/// ```262///263/// # Errors264///265/// This method will return an error if the number of arguments provided does not match266/// the number of arguments expected by the function's [`FunctionInfo`].267///268/// The function itself may also return any errors it needs to.269pub fn call_once(mut self, args: ArgList) -> FunctionResult {270self.call(args)271}272273/// Returns the function info.274pub fn info(&self) -> &FunctionInfo {275self.internal.info()276}277278/// The name of the function.279///280/// For [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],281/// the default name will always be the full path to the function as returned by [`core::any::type_name`],282/// unless the function is a closure, anonymous function, or function pointer,283/// in which case the name will be `None`.284///285/// This can be overridden using [`with_name`].286///287/// [`DynamicFunctionMuts`]: DynamicFunctionMut288/// [`with_name`]: Self::with_name289pub fn name(&self) -> Option<&Cow<'static, str>> {290self.internal.name()291}292293/// Returns `true` if the function is [overloaded].294///295/// # Example296///297/// ```298/// # use bevy_reflect::func::IntoFunctionMut;299/// let mut total_i32 = 0;300/// let increment = (|value: i32| total_i32 += value).into_function_mut();301/// assert!(!increment.is_overloaded());302///303/// let mut total_f32 = 0.0;304/// let increment = increment.with_overload(|value: f32| total_f32 += value);305/// assert!(increment.is_overloaded());306/// ```307///308/// [overloaded]: Self::with_overload309pub fn is_overloaded(&self) -> bool {310self.internal.is_overloaded()311}312313/// Returns the number of arguments the function expects.314///315/// For [overloaded] functions that can have a variable number of arguments,316/// this will contain the full set of counts for all signatures.317///318/// # Example319///320/// ```321/// # use bevy_reflect::func::IntoFunctionMut;322/// let add = (|a: i32, b: i32| a + b).into_function_mut();323/// assert!(add.arg_count().contains(2));324///325/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);326/// assert!(add.arg_count().contains(2));327/// assert!(add.arg_count().contains(3));328/// ```329///330/// [overloaded]: Self::with_overload331pub fn arg_count(&self) -> ArgCount {332self.internal.arg_count()333}334}335336/// Outputs the function's signature.337///338/// This takes the format: `DynamicFunctionMut(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.339///340/// Names for arguments and the function itself are optional and will default to `_` if not provided.341///342/// If the function is [overloaded], the output will include the signatures of all overloads as a set.343/// For example, `DynamicFunctionMut(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.344///345/// [overloaded]: DynamicFunctionMut::with_overload346impl<'env> Debug for DynamicFunctionMut<'env> {347fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {348write!(f, "DynamicFunctionMut({:?})", &self.internal)349}350}351352impl<'env> From<DynamicFunction<'env>> for DynamicFunctionMut<'env> {353#[inline]354fn from(function: DynamicFunction<'env>) -> Self {355Self {356internal: function.internal.map_functions(arc_to_box),357}358}359}360361/// Helper function from converting an [`Arc`] function to a [`Box`] function.362///363/// This is needed to help the compiler infer the correct types.364fn arc_to_box<'env>(365f: Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>,366) -> BoxFnMut<'env> {367Box::new(move |args| f(args))368}369370impl<'env> IntoFunctionMut<'env, ()> for DynamicFunctionMut<'env> {371#[inline]372fn into_function_mut(self) -> DynamicFunctionMut<'env> {373self374}375}376377#[cfg(test)]378mod tests {379use super::*;380use crate::func::{FunctionError, IntoReturn, SignatureInfo};381use alloc::vec;382use core::ops::Add;383384#[test]385fn should_overwrite_function_name() {386let mut total = 0;387let func = (|a: i32, b: i32| total = a + b).into_function_mut();388assert!(func.name().is_none());389390let func = func.with_name("my_function");391assert_eq!(func.name().unwrap(), "my_function");392}393394#[test]395fn should_convert_dynamic_function_mut_with_into_function() {396fn make_closure<'env, F: IntoFunctionMut<'env, M>, M>(f: F) -> DynamicFunctionMut<'env> {397f.into_function_mut()398}399400let mut total = 0;401let closure: DynamicFunctionMut = make_closure(|a: i32, b: i32| total = a + b);402let _: DynamicFunctionMut = make_closure(closure);403}404405#[test]406fn should_return_error_on_arg_count_mismatch() {407let mut total = 0;408let mut func = (|a: i32, b: i32| total = a + b).into_function_mut();409410let args = ArgList::default().with_owned(25_i32);411let error = func.call(args).unwrap_err();412assert_eq!(413error,414FunctionError::ArgCountMismatch {415expected: ArgCount::new(2).unwrap(),416received: 1417}418);419420let args = ArgList::default().with_owned(25_i32);421let error = func.call_once(args).unwrap_err();422assert_eq!(423error,424FunctionError::ArgCountMismatch {425expected: ArgCount::new(2).unwrap(),426received: 1427}428);429}430431#[test]432fn should_allow_creating_manual_generic_dynamic_function_mut() {433let mut total = 0_i32;434let func = DynamicFunctionMut::new(435|mut args| {436let value = args.take_arg()?;437438if value.is::<i32>() {439let value = value.take::<i32>()?;440total += value;441} else {442let value = value.take::<i16>()?;443total += value as i32;444}445446Ok(().into_return())447},448vec![449SignatureInfo::named("add::<i32>").with_arg::<i32>("value"),450SignatureInfo::named("add::<i16>").with_arg::<i16>("value"),451],452);453454assert_eq!(func.name().unwrap(), "add::<i32>");455let mut func = func.with_name("add");456assert_eq!(func.name().unwrap(), "add");457458let args = ArgList::default().with_owned(25_i32);459func.call(args).unwrap();460let args = ArgList::default().with_owned(75_i16);461func.call(args).unwrap();462463drop(func);464assert_eq!(total, 100);465}466467// Closures that mutably borrow from their environment cannot realistically468// be overloaded since that would break Rust's borrowing rules.469// However, we still need to verify overloaded functions work since a470// `DynamicFunctionMut` can also be made from a non-mutably borrowing closure/function.471#[test]472fn should_allow_function_overloading() {473fn add<T: Add<Output = T>>(a: T, b: T) -> T {474a + b475}476477let mut func = add::<i32>.into_function_mut().with_overload(add::<f32>);478479let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);480let result = func.call(args).unwrap().unwrap_owned();481assert_eq!(result.try_take::<i32>().unwrap(), 100);482483let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);484let result = func.call(args).unwrap().unwrap_owned();485assert_eq!(result.try_take::<f32>().unwrap(), 100.0);486}487}488489490