Path: blob/main/crates/bevy_reflect/src/func/dynamic_function.rs
6599 views
use crate::{1__macro_exports::RegisterForReflection,2func::{3args::{ArgCount, ArgList},4dynamic_function_internal::DynamicFunctionInternal,5info::FunctionInfo,6DynamicFunctionMut, Function, FunctionOverloadError, FunctionResult, IntoFunction,7IntoFunctionMut,8},9ApplyError, MaybeTyped, PartialReflect, Reflect, ReflectKind, ReflectMut, ReflectOwned,10ReflectRef, TypeInfo, TypePath,11};12use alloc::{borrow::Cow, boxed::Box};13use bevy_platform::sync::Arc;14use bevy_reflect_derive::impl_type_path;15use core::fmt::{Debug, Formatter};1617/// An [`Arc`] containing a callback to a reflected function.18///19/// The `Arc` is used to both ensure that it is `Send + Sync`20/// and to allow for the callback to be cloned.21///22/// Note that cloning is okay since we only ever need an immutable reference23/// to call a `dyn Fn` function.24/// If we were to contain a `dyn FnMut` instead, cloning would be a lot more complicated.25type ArcFn<'env> = Arc<dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>;2627/// A dynamic representation of a function.28///29/// This type can be used to represent any callable that satisfies [`Fn`]30/// (or the reflection-based equivalent, [`ReflectFn`]).31/// That is, any function or closure that does not mutably borrow data from its environment.32///33/// For functions that do need to capture their environment mutably (i.e. mutable closures),34/// see [`DynamicFunctionMut`].35///36/// See the [module-level documentation] for more information.37///38/// You will generally not need to construct this manually.39/// Instead, many functions and closures can be automatically converted using the [`IntoFunction`] trait.40///41/// # Example42///43/// Most of the time, a [`DynamicFunction`] can be created using the [`IntoFunction`] trait:44///45/// ```46/// # use bevy_reflect::func::{ArgList, DynamicFunction, IntoFunction};47/// #48/// fn add(a: i32, b: i32) -> i32 {49/// a + b50/// }51///52/// // Convert the function into a dynamic function using `IntoFunction::into_function`:53/// let mut func: DynamicFunction = add.into_function();54///55/// // Dynamically call it:56/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);57/// let value = func.call(args).unwrap().unwrap_owned();58///59/// // Check the result:60/// assert_eq!(value.try_downcast_ref::<i32>(), Some(&100));61/// ```62///63/// [`ReflectFn`]: crate::func::ReflectFn64/// [module-level documentation]: crate::func65#[derive(Clone)]66pub struct DynamicFunction<'env> {67pub(super) internal: DynamicFunctionInternal<ArcFn<'env>>,68}6970impl<'env> DynamicFunction<'env> {71/// Create a new [`DynamicFunction`].72///73/// The given function can be used to call out to any other callable,74/// including functions, closures, or methods.75///76/// It's important that the function signature matches the provided [`FunctionInfo`].77/// as this will be used to validate arguments when [calling] the function.78/// This is also required in order for [function overloading] to work correctly.79///80/// # Panics81///82/// This function may panic for any of the following reasons:83/// - No [`SignatureInfo`] is provided.84/// - A provided [`SignatureInfo`] has more arguments than [`ArgCount::MAX_COUNT`].85/// - The conversion to [`FunctionInfo`] fails.86///87/// [calling]: crate::func::dynamic_function::DynamicFunction::call88/// [`SignatureInfo`]: crate::func::SignatureInfo89/// [function overloading]: Self::with_overload90pub fn new<F: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env>(91func: F,92info: impl TryInto<FunctionInfo, Error: Debug>,93) -> Self {94let arc = Arc::new(func);9596#[cfg(not(target_has_atomic = "ptr"))]97#[expect(98unsafe_code,99reason = "unsized coercion is an unstable feature for non-std types"100)]101// SAFETY:102// - Coercion from `T` to `dyn for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`103// is valid as `T: for<'a> Fn(ArgList<'a>) -> FunctionResult<'a> + Send + Sync + 'env`104// - `Arc::from_raw` receives a valid pointer from a previous call to `Arc::into_raw`105let arc = unsafe { ArcFn::<'env>::from_raw(Arc::into_raw(arc) as *const _) };106107Self {108internal: DynamicFunctionInternal::new(arc, info.try_into().unwrap()),109}110}111112/// Set the name of the function.113///114/// For [`DynamicFunctions`] created using [`IntoFunction`],115/// the default name will always be the full path to the function as returned by [`core::any::type_name`],116/// unless the function is a closure, anonymous function, or function pointer,117/// in which case the name will be `None`.118///119/// [`DynamicFunctions`]: DynamicFunction120pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {121self.internal = self.internal.with_name(name);122self123}124125/// Add an overload to this function.126///127/// Overloads allow a single [`DynamicFunction`] to represent multiple functions of different signatures.128///129/// This can be used to handle multiple monomorphizations of a generic function130/// or to allow functions with a variable number of arguments.131///132/// Any functions with the same [argument signature] will be overwritten by the one from the new function, `F`.133/// For example, if the existing function had the signature `(i32, i32) -> i32`,134/// and the new function, `F`, also had the signature `(i32, i32) -> i32`,135/// the one from `F` would replace the one from the existing function.136///137/// Overloaded functions retain the [name] of the original function.138///139/// # Panics140///141/// Panics if the function, `F`, contains a signature already found in this function.142///143/// For a non-panicking version, see [`try_with_overload`].144///145/// # Examples146///147/// ```148/// # use std::ops::Add;149/// # use bevy_reflect::func::{ArgList, IntoFunction};150/// #151/// fn add<T: Add<Output = T>>(a: T, b: T) -> T {152/// a + b153/// }154///155/// // Currently, the only generic type `func` supports is `i32`:156/// let mut func = add::<i32>.into_function();157///158/// // However, we can add an overload to handle `f32` as well:159/// func = func.with_overload(add::<f32>);160///161/// // Test `i32`:162/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);163/// let result = func.call(args).unwrap().unwrap_owned();164/// assert_eq!(result.try_take::<i32>().unwrap(), 100);165///166/// // Test `f32`:167/// let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);168/// let result = func.call(args).unwrap().unwrap_owned();169/// assert_eq!(result.try_take::<f32>().unwrap(), 100.0);170///```171///172/// ```173/// # use bevy_reflect::func::{ArgList, IntoFunction};174/// #175/// fn add_2(a: i32, b: i32) -> i32 {176/// a + b177/// }178///179/// fn add_3(a: i32, b: i32, c: i32) -> i32 {180/// a + b + c181/// }182///183/// // Currently, `func` only supports two arguments.184/// let mut func = add_2.into_function();185///186/// // However, we can add an overload to handle three arguments as well.187/// func = func.with_overload(add_3);188///189/// // Test two arguments:190/// let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);191/// let result = func.call(args).unwrap().unwrap_owned();192/// assert_eq!(result.try_take::<i32>().unwrap(), 100);193///194/// // Test three arguments:195/// let args = ArgList::default()196/// .with_owned(25_i32)197/// .with_owned(75_i32)198/// .with_owned(100_i32);199/// let result = func.call(args).unwrap().unwrap_owned();200/// assert_eq!(result.try_take::<i32>().unwrap(), 200);201/// ```202///203///```should_panic204/// # use bevy_reflect::func::IntoFunction;205///206/// fn add(a: i32, b: i32) -> i32 {207/// a + b208/// }209///210/// fn sub(a: i32, b: i32) -> i32 {211/// a - b212/// }213///214/// let mut func = add.into_function();215///216/// // This will panic because the function already has an argument signature for `(i32, i32)`:217/// func = func.with_overload(sub);218/// ```219///220/// [argument signature]: crate::func::signature::ArgumentSignature221/// [name]: Self::name222/// [`try_with_overload`]: Self::try_with_overload223pub fn with_overload<'a, F: IntoFunction<'a, Marker>, Marker>(224self,225function: F,226) -> DynamicFunction<'a>227where228'env: 'a,229{230self.try_with_overload(function).unwrap_or_else(|(_, err)| {231panic!("{}", err);232})233}234235/// Attempt to add an overload to this function.236///237/// If the function, `F`, contains a signature already found in this function,238/// an error will be returned along with the original function.239///240/// For a panicking version, see [`with_overload`].241///242/// [`with_overload`]: Self::with_overload243pub fn try_with_overload<F: IntoFunction<'env, Marker>, Marker>(244mut self,245function: F,246) -> Result<Self, (Box<Self>, FunctionOverloadError)> {247let function = function.into_function();248249match self.internal.merge(function.internal) {250Ok(_) => Ok(self),251Err(err) => Err((Box::new(self), err)),252}253}254255/// Call the function with the given arguments.256///257/// # Example258///259/// ```260/// # use bevy_reflect::func::{IntoFunction, ArgList};261/// let c = 23;262/// let add = |a: i32, b: i32| -> i32 {263/// a + b + c264/// };265///266/// let mut func = add.into_function().with_name("add");267/// let args = ArgList::new().with_owned(25_i32).with_owned(75_i32);268/// let result = func.call(args).unwrap().unwrap_owned();269/// assert_eq!(result.try_take::<i32>().unwrap(), 123);270/// ```271///272/// # Errors273///274/// This method will return an error if the number of arguments provided does not match275/// the number of arguments expected by the function's [`FunctionInfo`].276///277/// The function itself may also return any errors it needs to.278pub fn call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {279self.internal.validate_args(&args)?;280let func = self.internal.get(&args)?;281func(args)282}283284/// Returns the function info.285pub fn info(&self) -> &FunctionInfo {286self.internal.info()287}288289/// The name of the function.290///291/// For [`DynamicFunctions`] created using [`IntoFunction`],292/// the default name will always be the full path to the function as returned by [`core::any::type_name`],293/// unless the function is a closure, anonymous function, or function pointer,294/// in which case the name will be `None`.295///296/// This can be overridden using [`with_name`].297///298/// If the function was [overloaded], it will retain its original name if it had one.299///300/// [`DynamicFunctions`]: DynamicFunction301/// [`with_name`]: Self::with_name302/// [overloaded]: Self::with_overload303pub fn name(&self) -> Option<&Cow<'static, str>> {304self.internal.name()305}306307/// Returns `true` if the function is [overloaded].308///309/// # Example310///311/// ```312/// # use bevy_reflect::func::IntoFunction;313/// let add = (|a: i32, b: i32| a + b).into_function();314/// assert!(!add.is_overloaded());315///316/// let add = add.with_overload(|a: f32, b: f32| a + b);317/// assert!(add.is_overloaded());318/// ```319///320/// [overloaded]: Self::with_overload321pub fn is_overloaded(&self) -> bool {322self.internal.is_overloaded()323}324/// Returns the number of arguments the function expects.325///326/// For [overloaded] functions that can have a variable number of arguments,327/// this will contain the full set of counts for all signatures.328///329/// # Example330///331/// ```332/// # use bevy_reflect::func::IntoFunction;333/// let add = (|a: i32, b: i32| a + b).into_function();334/// assert!(add.arg_count().contains(2));335///336/// let add = add.with_overload(|a: f32, b: f32, c: f32| a + b + c);337/// assert!(add.arg_count().contains(2));338/// assert!(add.arg_count().contains(3));339/// ```340///341/// [overloaded]: Self::with_overload342pub fn arg_count(&self) -> ArgCount {343self.internal.arg_count()344}345}346347impl Function for DynamicFunction<'static> {348fn name(&self) -> Option<&Cow<'static, str>> {349self.internal.name()350}351352fn info(&self) -> &FunctionInfo {353self.internal.info()354}355356fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a> {357self.call(args)358}359360fn to_dynamic_function(&self) -> DynamicFunction<'static> {361self.clone()362}363}364365impl PartialReflect for DynamicFunction<'static> {366fn get_represented_type_info(&self) -> Option<&'static TypeInfo> {367None368}369370fn into_partial_reflect(self: Box<Self>) -> Box<dyn PartialReflect> {371self372}373374fn as_partial_reflect(&self) -> &dyn PartialReflect {375self376}377378fn as_partial_reflect_mut(&mut self) -> &mut dyn PartialReflect {379self380}381382fn try_into_reflect(self: Box<Self>) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>> {383Err(self)384}385386fn try_as_reflect(&self) -> Option<&dyn Reflect> {387None388}389390fn try_as_reflect_mut(&mut self) -> Option<&mut dyn Reflect> {391None392}393394fn try_apply(&mut self, value: &dyn PartialReflect) -> Result<(), ApplyError> {395match value.reflect_ref() {396ReflectRef::Function(func) => {397*self = func.to_dynamic_function();398Ok(())399}400_ => Err(ApplyError::MismatchedTypes {401from_type: value.reflect_type_path().into(),402to_type: Self::type_path().into(),403}),404}405}406407fn reflect_kind(&self) -> ReflectKind {408ReflectKind::Function409}410411fn reflect_ref(&self) -> ReflectRef<'_> {412ReflectRef::Function(self)413}414415fn reflect_mut(&mut self) -> ReflectMut<'_> {416ReflectMut::Function(self)417}418419fn reflect_owned(self: Box<Self>) -> ReflectOwned {420ReflectOwned::Function(self)421}422423fn reflect_hash(&self) -> Option<u64> {424None425}426427fn reflect_partial_eq(&self, _value: &dyn PartialReflect) -> Option<bool> {428None429}430431fn debug(&self, f: &mut Formatter<'_>) -> core::fmt::Result {432Debug::fmt(self, f)433}434435fn is_dynamic(&self) -> bool {436true437}438}439440impl MaybeTyped for DynamicFunction<'static> {}441442impl RegisterForReflection for DynamicFunction<'static> {}443444impl_type_path!((in bevy_reflect) DynamicFunction<'env>);445446/// Outputs the function's signature.447///448/// This takes the format: `DynamicFunction(fn {name}({arg1}: {type1}, {arg2}: {type2}, ...) -> {return_type})`.449///450/// Names for arguments and the function itself are optional and will default to `_` if not provided.451///452/// If the function is [overloaded], the output will include the signatures of all overloads as a set.453/// For example, `DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})`.454///455/// [overloaded]: DynamicFunction::with_overload456impl<'env> Debug for DynamicFunction<'env> {457fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {458write!(f, "DynamicFunction({:?})", &self.internal)459}460}461462impl<'env> IntoFunction<'env, ()> for DynamicFunction<'env> {463#[inline]464fn into_function(self) -> DynamicFunction<'env> {465self466}467}468469impl<'env> IntoFunctionMut<'env, ()> for DynamicFunction<'env> {470#[inline]471fn into_function_mut(self) -> DynamicFunctionMut<'env> {472DynamicFunctionMut::from(self)473}474}475476#[cfg(test)]477mod tests {478use super::*;479use crate::func::signature::ArgumentSignature;480use crate::func::{FunctionError, IntoReturn, SignatureInfo};481use crate::Type;482use alloc::{format, string::String, vec, vec::Vec};483use bevy_platform::collections::HashSet;484use core::ops::Add;485486#[test]487fn should_overwrite_function_name() {488let c = 23;489let func = (|a: i32, b: i32| a + b + c).into_function();490assert!(func.name().is_none());491492let func = func.with_name("my_function");493assert_eq!(func.name().unwrap(), "my_function");494}495496#[test]497fn should_convert_dynamic_function_with_into_function() {498fn make_closure<'env, F: IntoFunction<'env, M>, M>(f: F) -> DynamicFunction<'env> {499f.into_function()500}501502let c = 23;503let function: DynamicFunction = make_closure(|a: i32, b: i32| a + b + c);504let _: DynamicFunction = make_closure(function);505}506507#[test]508fn should_return_error_on_arg_count_mismatch() {509let func = (|a: i32, b: i32| a + b).into_function();510511let args = ArgList::default().with_owned(25_i32);512let error = func.call(args).unwrap_err();513514assert_eq!(515error,516FunctionError::ArgCountMismatch {517expected: ArgCount::new(2).unwrap(),518received: 1519}520);521}522523#[test]524fn should_return_error_on_arg_count_mismatch_overloaded() {525let func = (|a: i32, b: i32| a + b)526.into_function()527.with_overload(|a: i32, b: i32, c: i32| a + b + c);528529let args = ArgList::default()530.with_owned(1_i32)531.with_owned(2_i32)532.with_owned(3_i32)533.with_owned(4_i32);534535let error = func.call(args).unwrap_err();536537let mut expected_count = ArgCount::new(2).unwrap();538expected_count.add(3);539540assert_eq!(541error,542FunctionError::ArgCountMismatch {543expected: expected_count,544received: 4545}546);547}548549#[test]550fn should_clone_dynamic_function() {551let hello = String::from("Hello");552553let greet = |name: &String| -> String { format!("{hello}, {name}!") };554555let greet = greet.into_function().with_name("greet");556let clone = greet.clone();557558assert_eq!(greet.name().unwrap(), "greet");559assert_eq!(clone.name().unwrap(), "greet");560561let cloned_value = clone562.call(ArgList::default().with_ref(&String::from("world")))563.unwrap()564.unwrap_owned()565.try_take::<String>()566.unwrap();567568assert_eq!(cloned_value, "Hello, world!");569}570571#[test]572fn should_apply_function() {573let mut func: Box<dyn Function> = Box::new((|a: i32, b: i32| a + b).into_function());574func.apply(&((|a: i32, b: i32| a * b).into_function()));575576let args = ArgList::new().with_owned(5_i32).with_owned(5_i32);577let result = func.reflect_call(args).unwrap().unwrap_owned();578assert_eq!(result.try_take::<i32>().unwrap(), 25);579}580581#[test]582fn should_allow_recursive_dynamic_function() {583let factorial = DynamicFunction::new(584|mut args| {585let curr = args.pop::<i32>()?;586if curr == 0 {587return Ok(1_i32.into_return());588}589590let arg = args.pop_arg()?;591let this = arg.value();592593match this.reflect_ref() {594ReflectRef::Function(func) => {595let result = func.reflect_call(596ArgList::new()597.with_ref(this.as_partial_reflect())598.with_owned(curr - 1),599);600let value = result.unwrap().unwrap_owned().try_take::<i32>().unwrap();601Ok((curr * value).into_return())602}603_ => panic!("expected function"),604}605},606// The `FunctionInfo` doesn't really matter for this test607// so we can just give it dummy information.608SignatureInfo::anonymous()609.with_arg::<i32>("curr")610.with_arg::<()>("this"),611);612613let args = ArgList::new().with_ref(&factorial).with_owned(5_i32);614let value = factorial.call(args).unwrap().unwrap_owned();615assert_eq!(value.try_take::<i32>().unwrap(), 120);616}617618#[test]619fn should_allow_creating_manual_generic_dynamic_function() {620let func = DynamicFunction::new(621|mut args| {622let a = args.take_arg()?;623let b = args.take_arg()?;624625if a.is::<i32>() {626let a = a.take::<i32>()?;627let b = b.take::<i32>()?;628Ok((a + b).into_return())629} else {630let a = a.take::<f32>()?;631let b = b.take::<f32>()?;632Ok((a + b).into_return())633}634},635vec![636SignatureInfo::named("add::<i32>")637.with_arg::<i32>("a")638.with_arg::<i32>("b")639.with_return::<i32>(),640SignatureInfo::named("add::<f32>")641.with_arg::<f32>("a")642.with_arg::<f32>("b")643.with_return::<f32>(),644],645);646647assert_eq!(func.name().unwrap(), "add::<i32>");648let func = func.with_name("add");649assert_eq!(func.name().unwrap(), "add");650651let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);652let result = func.call(args).unwrap().unwrap_owned();653assert_eq!(result.try_take::<i32>().unwrap(), 100);654655let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);656let result = func.call(args).unwrap().unwrap_owned();657assert_eq!(result.try_take::<f32>().unwrap(), 100.0);658}659660#[test]661#[should_panic(expected = "called `Result::unwrap()` on an `Err` value: MissingSignature")]662fn should_panic_on_missing_function_info() {663let _ = DynamicFunction::new(|_| Ok(().into_return()), Vec::new());664}665666#[test]667fn should_allow_function_overloading() {668fn add<T: Add<Output = T>>(a: T, b: T) -> T {669a + b670}671672let func = add::<i32>.into_function().with_overload(add::<f32>);673674let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);675let result = func.call(args).unwrap().unwrap_owned();676assert_eq!(result.try_take::<i32>().unwrap(), 100);677678let args = ArgList::default().with_owned(25.0_f32).with_owned(75.0_f32);679let result = func.call(args).unwrap().unwrap_owned();680assert_eq!(result.try_take::<f32>().unwrap(), 100.0);681}682683#[test]684fn should_allow_variable_arguments_via_overloading() {685fn add_2(a: i32, b: i32) -> i32 {686a + b687}688689fn add_3(a: i32, b: i32, c: i32) -> i32 {690a + b + c691}692693let func = add_2.into_function().with_overload(add_3);694695let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);696let result = func.call(args).unwrap().unwrap_owned();697assert_eq!(result.try_take::<i32>().unwrap(), 100);698699let args = ArgList::default()700.with_owned(25_i32)701.with_owned(75_i32)702.with_owned(100_i32);703let result = func.call(args).unwrap().unwrap_owned();704assert_eq!(result.try_take::<i32>().unwrap(), 200);705}706707#[test]708fn should_allow_function_overloading_with_manual_overload() {709let manual = DynamicFunction::new(710|mut args| {711let a = args.take_arg()?;712let b = args.take_arg()?;713714if a.is::<i32>() {715let a = a.take::<i32>()?;716let b = b.take::<i32>()?;717Ok((a + b).into_return())718} else {719let a = a.take::<f32>()?;720let b = b.take::<f32>()?;721Ok((a + b).into_return())722}723},724vec![725SignatureInfo::named("add::<i32>")726.with_arg::<i32>("a")727.with_arg::<i32>("b")728.with_return::<i32>(),729SignatureInfo::named("add::<f32>")730.with_arg::<f32>("a")731.with_arg::<f32>("b")732.with_return::<f32>(),733],734);735736let func = manual.with_overload(|a: u32, b: u32| a + b);737738let args = ArgList::default().with_owned(25_i32).with_owned(75_i32);739let result = func.call(args).unwrap().unwrap_owned();740assert_eq!(result.try_take::<i32>().unwrap(), 100);741742let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);743let result = func.call(args).unwrap().unwrap_owned();744assert_eq!(result.try_take::<u32>().unwrap(), 100);745}746747#[test]748fn should_return_error_on_unknown_overload() {749fn add<T: Add<Output = T>>(a: T, b: T) -> T {750a + b751}752753let func = add::<i32>.into_function().with_overload(add::<f32>);754755let args = ArgList::default().with_owned(25_u32).with_owned(75_u32);756let result = func.call(args);757assert_eq!(758result.unwrap_err(),759FunctionError::NoOverload {760expected: [761ArgumentSignature::from_iter(vec![Type::of::<i32>(), Type::of::<i32>()]),762ArgumentSignature::from_iter(vec![Type::of::<f32>(), Type::of::<f32>()])763]764.into_iter()765.collect::<HashSet<_>>(),766received: ArgumentSignature::from_iter(vec![Type::of::<u32>(), Type::of::<u32>()]),767}768);769}770771#[test]772fn should_debug_dynamic_function() {773fn greet(name: &String) -> String {774format!("Hello, {name}!")775}776777let function = greet.into_function();778let debug = format!("{function:?}");779assert_eq!(debug, "DynamicFunction(fn bevy_reflect::func::dynamic_function::tests::should_debug_dynamic_function::greet(_: &alloc::string::String) -> alloc::string::String)");780}781782#[test]783fn should_debug_anonymous_dynamic_function() {784let function = (|a: i32, b: i32| a + b).into_function();785let debug = format!("{function:?}");786assert_eq!(debug, "DynamicFunction(fn _(_: i32, _: i32) -> i32)");787}788789#[test]790fn should_debug_overloaded_dynamic_function() {791fn add<T: Add<Output = T>>(a: T, b: T) -> T {792a + b793}794795let function = add::<i32>796.into_function()797.with_overload(add::<f32>)798.with_name("add");799let debug = format!("{function:?}");800assert_eq!(801debug,802"DynamicFunction(fn add{(_: i32, _: i32) -> i32, (_: f32, _: f32) -> f32})"803);804}805}806807808