use alloc::{borrow::Cow, boxed::Box, vec, vec::Vec};1use core::fmt::{Debug, Formatter};23use crate::{4func::args::{ArgCount, ArgCountOutOfBoundsError, ArgInfo, GetOwnership, Ownership},5func::signature::ArgumentSignature,6func::FunctionOverloadError,7type_info::impl_type_methods,8Type, TypePath,9};1011use variadics_please::all_tuples;1213/// Type information for a [`DynamicFunction`] or [`DynamicFunctionMut`].14///15/// This information can be retrieved directly from certain functions and closures16/// using the [`TypedFunction`] trait, and manually constructed otherwise.17///18/// It is compromised of one or more [`SignatureInfo`] structs,19/// allowing it to represent functions with multiple sets of arguments (i.e. "overloaded functions").20///21/// [`DynamicFunction`]: crate::func::DynamicFunction22/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut23#[derive(Debug, Clone)]24pub struct FunctionInfo {25name: Option<Cow<'static, str>>,26arg_count: ArgCount,27signatures: Box<[SignatureInfo]>,28}2930impl FunctionInfo {31/// Create a new [`FunctionInfo`] for a function with the given signature.32///33/// # Panics34///35/// Panics if the given signature has more than the maximum number of arguments36/// as specified by [`ArgCount::MAX_COUNT`].37pub fn new(signature: SignatureInfo) -> Self {38Self {39name: signature.name.clone(),40arg_count: ArgCount::new(signature.arg_count()).unwrap(),41signatures: vec![signature].into(),42}43}4445/// Create a new [`FunctionInfo`] from a set of signatures.46///47/// Returns an error if the given iterator is empty or contains duplicate signatures.48pub fn try_from_iter(49signatures: impl IntoIterator<Item = SignatureInfo>,50) -> Result<Self, FunctionOverloadError> {51let mut iter = signatures.into_iter();5253let base = iter.next().ok_or(FunctionOverloadError::MissingSignature)?;5455if base.arg_count() > ArgCount::MAX_COUNT {56return Err(FunctionOverloadError::TooManyArguments(57ArgumentSignature::from(&base),58));59}6061let mut info = Self::new(base);6263for signature in iter {64if signature.arg_count() > ArgCount::MAX_COUNT {65return Err(FunctionOverloadError::TooManyArguments(66ArgumentSignature::from(&signature),67));68}6970info = info.with_overload(signature).map_err(|sig| {71FunctionOverloadError::DuplicateSignature(ArgumentSignature::from(&sig))72})?;73}7475Ok(info)76}7778/// The base signature for this function.79///80/// All functions—including overloaded functions—are guaranteed to have at least one signature.81/// The first signature used to define the [`FunctionInfo`] is considered the base signature.82pub fn base(&self) -> &SignatureInfo {83&self.signatures[0]84}8586/// Whether this function is overloaded.87///88/// This is determined by the existence of multiple signatures.89pub fn is_overloaded(&self) -> bool {90self.signatures.len() > 191}9293/// Set the name of the function.94pub fn with_name(mut self, name: Option<impl Into<Cow<'static, str>>>) -> Self {95self.name = name.map(Into::into);96self97}9899/// The name of the function.100///101/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],102/// the default name will always be the full path to the function as returned by [`std::any::type_name`],103/// unless the function is a closure, anonymous function, or function pointer,104/// in which case the name will be `None`.105///106/// For overloaded functions, this will be the name of the base signature,107/// unless manually overwritten using [`Self::with_name`].108///109/// [`DynamicFunctions`]: crate::func::DynamicFunction110/// [`IntoFunction`]: crate::func::IntoFunction111/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut112/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut113pub fn name(&self) -> Option<&Cow<'static, str>> {114self.name.as_ref()115}116117/// Add a signature to this function.118///119/// If a signature with the same [`ArgumentSignature`] already exists,120/// an error is returned with the given signature.121///122/// # Panics123///124/// Panics if the given signature has more than the maximum number of arguments125/// as specified by [`ArgCount::MAX_COUNT`].126pub fn with_overload(mut self, signature: SignatureInfo) -> Result<Self, SignatureInfo> {127let is_duplicate = self.signatures.iter().any(|s| {128s.arg_count() == signature.arg_count()129&& ArgumentSignature::from(s) == ArgumentSignature::from(&signature)130});131132if is_duplicate {133return Err(signature);134}135136self.arg_count.add(signature.arg_count());137self.signatures = IntoIterator::into_iter(self.signatures)138.chain(Some(signature))139.collect();140Ok(self)141}142143/// Returns the number of arguments the function expects.144///145/// For [overloaded] functions that can have a variable number of arguments,146/// this will contain the full set of counts for all signatures.147///148/// [overloaded]: crate::func#overloading-functions149pub fn arg_count(&self) -> ArgCount {150self.arg_count151}152153/// The signatures of the function.154///155/// This is guaranteed to always contain at least one signature.156/// Overloaded functions will contain two or more.157pub fn signatures(&self) -> &[SignatureInfo] {158&self.signatures159}160161/// Returns a wrapper around this info that implements [`Debug`] for pretty-printing the function.162///163/// This can be useful for more readable debugging and logging.164///165/// # Example166///167/// ```168/// # use bevy_reflect::func::{FunctionInfo, TypedFunction};169/// #170/// fn add(a: i32, b: i32) -> i32 {171/// a + b172/// }173///174/// let info = add.get_function_info();175///176/// let pretty = info.pretty_printer();177/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");178/// ```179pub fn pretty_printer(&self) -> PrettyPrintFunctionInfo<'_> {180PrettyPrintFunctionInfo::new(self)181}182183/// Extend this [`FunctionInfo`] with another without checking for duplicates.184///185/// # Panics186///187/// Panics if the given signature has more than the maximum number of arguments188/// as specified by [`ArgCount::MAX_COUNT`].189pub(super) fn extend_unchecked(&mut self, other: FunctionInfo) {190if self.name.is_none() {191self.name = other.name;192}193194let signatures = core::mem::take(&mut self.signatures);195self.signatures = IntoIterator::into_iter(signatures)196.chain(IntoIterator::into_iter(other.signatures))197.collect();198self.arg_count = self199.signatures200.iter()201.fold(ArgCount::default(), |mut count, sig| {202count.add(sig.arg_count());203count204});205}206}207208impl TryFrom<SignatureInfo> for FunctionInfo {209type Error = ArgCountOutOfBoundsError;210211fn try_from(signature: SignatureInfo) -> Result<Self, Self::Error> {212let count = signature.arg_count();213if count > ArgCount::MAX_COUNT {214return Err(ArgCountOutOfBoundsError(count));215}216217Ok(Self::new(signature))218}219}220221impl TryFrom<Vec<SignatureInfo>> for FunctionInfo {222type Error = FunctionOverloadError;223224fn try_from(signatures: Vec<SignatureInfo>) -> Result<Self, Self::Error> {225Self::try_from_iter(signatures)226}227}228229impl<const N: usize> TryFrom<[SignatureInfo; N]> for FunctionInfo {230type Error = FunctionOverloadError;231232fn try_from(signatures: [SignatureInfo; N]) -> Result<Self, Self::Error> {233Self::try_from_iter(signatures)234}235}236237/// Type information for the signature of a [`DynamicFunction`] or [`DynamicFunctionMut`].238///239/// Every [`FunctionInfo`] contains one or more [`SignatureInfo`]s.240///241/// [`DynamicFunction`]: crate::func::DynamicFunction242/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut243#[derive(Debug, Clone)]244pub struct SignatureInfo {245name: Option<Cow<'static, str>>,246args: Box<[ArgInfo]>,247return_info: ReturnInfo,248}249250impl SignatureInfo {251/// Create a new [`SignatureInfo`] for a function with the given name.252pub fn named(name: impl Into<Cow<'static, str>>) -> Self {253Self {254name: Some(name.into()),255args: Box::new([]),256return_info: ReturnInfo::new::<()>(),257}258}259260/// Create a new [`SignatureInfo`] with no name.261///262/// For the purposes of debugging and [registration],263/// it's recommended to use [`Self::named`] instead.264///265/// [registration]: crate::func::FunctionRegistry266pub fn anonymous() -> Self {267Self {268name: None,269args: Box::new([]),270return_info: ReturnInfo::new::<()>(),271}272}273274/// Set the name of the function.275pub fn with_name(mut self, name: impl Into<Cow<'static, str>>) -> Self {276self.name = Some(name.into());277self278}279280/// Push an argument onto the function's argument list.281///282/// The order in which this method is called matters as it will determine the index of the argument283/// based on the current number of arguments.284pub fn with_arg<T: TypePath + GetOwnership>(285mut self,286name: impl Into<Cow<'static, str>>,287) -> Self {288let index = self.args.len();289self.args = IntoIterator::into_iter(self.args)290.chain(Some(ArgInfo::new::<T>(index).with_name(name)))291.collect();292self293}294295/// Set the arguments of the function.296///297/// This will completely replace any existing arguments.298///299/// It's preferable to use [`Self::with_arg`] to add arguments to the function300/// as it will automatically set the index of the argument.301pub fn with_args(mut self, args: Vec<ArgInfo>) -> Self {302self.args = IntoIterator::into_iter(self.args).chain(args).collect();303self304}305306/// Set the [return information] of the function.307///308/// To manually set the [`ReturnInfo`] of the function, see [`Self::with_return_info`].309///310/// [return information]: ReturnInfo311pub fn with_return<T: TypePath + GetOwnership>(mut self) -> Self {312self.return_info = ReturnInfo::new::<T>();313self314}315316/// Set the [return information] of the function.317///318/// This will completely replace any existing return information.319///320/// For a simpler, static version of this method, see [`Self::with_return`].321///322/// [return information]: ReturnInfo323pub fn with_return_info(mut self, return_info: ReturnInfo) -> Self {324self.return_info = return_info;325self326}327328/// The name of the function.329///330/// For [`DynamicFunctions`] created using [`IntoFunction`] or [`DynamicFunctionMuts`] created using [`IntoFunctionMut`],331/// the default name will always be the full path to the function as returned by [`core::any::type_name`],332/// unless the function is a closure, anonymous function, or function pointer,333/// in which case the name will be `None`.334///335/// [`DynamicFunctions`]: crate::func::DynamicFunction336/// [`IntoFunction`]: crate::func::IntoFunction337/// [`DynamicFunctionMuts`]: crate::func::DynamicFunctionMut338/// [`IntoFunctionMut`]: crate::func::IntoFunctionMut339pub fn name(&self) -> Option<&Cow<'static, str>> {340self.name.as_ref()341}342343/// The arguments of the function.344pub fn args(&self) -> &[ArgInfo] {345&self.args346}347348/// The number of arguments the function takes.349pub fn arg_count(&self) -> usize {350self.args.len()351}352353/// The return information of the function.354pub fn return_info(&self) -> &ReturnInfo {355&self.return_info356}357}358359/// Information about the return type of a [`DynamicFunction`] or [`DynamicFunctionMut`].360///361/// [`DynamicFunction`]: crate::func::DynamicFunction362/// [`DynamicFunctionMut`]: crate::func::DynamicFunctionMut363#[derive(Debug, Clone)]364pub struct ReturnInfo {365ty: Type,366ownership: Ownership,367}368369impl ReturnInfo {370/// Create a new [`ReturnInfo`] representing the given type, `T`.371pub fn new<T: TypePath + GetOwnership>() -> Self {372Self {373ty: Type::of::<T>(),374ownership: T::ownership(),375}376}377378impl_type_methods!(ty);379380/// The ownership of this type.381pub fn ownership(&self) -> Ownership {382self.ownership383}384}385386/// A wrapper around [`FunctionInfo`] that implements [`Debug`] for pretty-printing function information.387///388/// # Example389///390/// ```391/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintFunctionInfo, TypedFunction};392/// #393/// fn add(a: i32, b: i32) -> i32 {394/// a + b395/// }396///397/// let info = add.get_function_info();398///399/// let pretty = PrettyPrintFunctionInfo::new(&info);400/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");401/// ```402pub struct PrettyPrintFunctionInfo<'a> {403info: &'a FunctionInfo,404include_fn_token: bool,405include_name: bool,406}407408impl<'a> PrettyPrintFunctionInfo<'a> {409/// Create a new pretty-printer for the given [`FunctionInfo`].410pub fn new(info: &'a FunctionInfo) -> Self {411Self {412info,413include_fn_token: false,414include_name: false,415}416}417418/// Include the function name in the pretty-printed output.419pub fn include_name(mut self) -> Self {420self.include_name = true;421self422}423424/// Include the `fn` token in the pretty-printed output.425pub fn include_fn_token(mut self) -> Self {426self.include_fn_token = true;427self428}429}430431impl<'a> Debug for PrettyPrintFunctionInfo<'a> {432fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {433if self.include_fn_token {434write!(f, "fn")?;435436if self.include_name {437write!(f, " ")?;438}439}440441match (self.include_name, self.info.name()) {442(true, Some(name)) => write!(f, "{name}")?,443(true, None) => write!(f, "_")?,444_ => {}445}446447if self.info.is_overloaded() {448// `{(arg0: i32, arg1: i32) -> (), (arg0: f32, arg1: f32) -> ()}`449let mut set = f.debug_set();450for signature in self.info.signatures() {451set.entry(&PrettyPrintSignatureInfo::new(signature));452}453set.finish()454} else {455// `(arg0: i32, arg1: i32) -> ()`456PrettyPrintSignatureInfo::new(self.info.base()).fmt(f)457}458}459}460461/// A wrapper around [`SignatureInfo`] that implements [`Debug`] for pretty-printing function signature information.462///463/// # Example464///465/// ```466/// # use bevy_reflect::func::{FunctionInfo, PrettyPrintSignatureInfo, TypedFunction};467/// #468/// fn add(a: i32, b: i32) -> i32 {469/// a + b470/// }471///472/// let info = add.get_function_info();473///474/// let pretty = PrettyPrintSignatureInfo::new(info.base());475/// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");476/// ```477pub struct PrettyPrintSignatureInfo<'a> {478info: &'a SignatureInfo,479include_fn_token: bool,480include_name: bool,481}482483impl<'a> PrettyPrintSignatureInfo<'a> {484/// Create a new pretty-printer for the given [`SignatureInfo`].485pub fn new(info: &'a SignatureInfo) -> Self {486Self {487info,488include_fn_token: false,489include_name: false,490}491}492493/// Include the function name in the pretty-printed output.494pub fn include_name(mut self) -> Self {495self.include_name = true;496self497}498499/// Include the `fn` token in the pretty-printed output.500pub fn include_fn_token(mut self) -> Self {501self.include_fn_token = true;502self503}504}505506impl<'a> Debug for PrettyPrintSignatureInfo<'a> {507fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {508if self.include_fn_token {509write!(f, "fn")?;510511if self.include_name {512write!(f, " ")?;513}514}515516match (self.include_name, self.info.name()) {517(true, Some(name)) => write!(f, "{name}")?,518(true, None) => write!(f, "_")?,519_ => {}520}521522write!(f, "(")?;523524// We manually write the args instead of using `DebugTuple` to avoid trailing commas525// and (when used with `{:#?}`) unnecessary newlines526for (index, arg) in self.info.args().iter().enumerate() {527if index > 0 {528write!(f, ", ")?;529}530531let name = arg.name().unwrap_or("_");532let ty = arg.type_path();533write!(f, "{name}: {ty}")?;534}535536let ret = self.info.return_info().type_path();537write!(f, ") -> {ret}")538}539}540541/// A static accessor to compile-time type information for functions.542///543/// This is the equivalent of [`Typed`], but for function.544///545/// # Blanket Implementation546///547/// This trait has a blanket implementation that covers:548/// - Functions and methods defined with the `fn` keyword549/// - Anonymous functions550/// - Function pointers551/// - Closures that capture immutable references to their environment552/// - Closures that capture mutable references to their environment553/// - Closures that take ownership of captured variables554///555/// For each of the above cases, the function signature may only have up to 15 arguments,556/// not including an optional receiver argument (often `&self` or `&mut self`).557/// This optional receiver argument may be either a mutable or immutable reference to a type.558/// If the return type is also a reference, its lifetime will be bound to the lifetime of this receiver.559///560/// See the [module-level documentation] for more information on valid signatures.561///562/// Arguments and the return type are expected to implement both [`GetOwnership`] and [`TypePath`].563/// By default, these traits are automatically implemented when using the `Reflect` [derive macro].564///565/// # Example566///567/// ```568/// # use bevy_reflect::func::{ArgList, ReflectFnMut, TypedFunction};569/// #570/// fn print(value: String) {571/// println!("{}", value);572/// }573///574/// let info = print.get_function_info();575/// assert!(info.name().unwrap().ends_with("print"));576/// assert!(info.arg_count().contains(1));577/// assert_eq!(info.base().args()[0].type_path(), "alloc::string::String");578/// assert_eq!(info.base().return_info().type_path(), "()");579/// ```580///581/// # Trait Parameters582///583/// This trait has a `Marker` type parameter that is used to get around issues with584/// [unconstrained type parameters] when defining impls with generic arguments or return types.585/// This `Marker` can be any type, provided it doesn't conflict with other implementations.586///587/// [module-level documentation]: crate::func588/// [`Typed`]: crate::Typed589/// [unconstrained type parameters]: https://doc.rust-lang.org/error_codes/E0207.html590pub trait TypedFunction<Marker> {591/// Get the [`FunctionInfo`] for this type.592fn function_info() -> FunctionInfo;593594/// Get the [`FunctionInfo`] for this type.595fn get_function_info(&self) -> FunctionInfo {596Self::function_info()597}598}599600/// Helper macro for implementing [`TypedFunction`] on Rust functions.601///602/// This currently implements it for the following signatures (where `argX` may be any of `T`, `&T`, or `&mut T`):603/// - `FnMut(arg0, arg1, ..., argN) -> R`604/// - `FnMut(&Receiver, arg0, arg1, ..., argN) -> &R`605/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &mut R`606/// - `FnMut(&mut Receiver, arg0, arg1, ..., argN) -> &R`607macro_rules! impl_typed_function {608($(($Arg:ident, $arg:ident)),*) => {609// === (...) -> ReturnType === //610impl<$($Arg,)* ReturnType, Function> TypedFunction<fn($($Arg),*) -> [ReturnType]> for Function611where612$($Arg: TypePath + GetOwnership,)*613ReturnType: TypePath + GetOwnership,614Function: FnMut($($Arg),*) -> ReturnType,615{616fn function_info() -> FunctionInfo {617FunctionInfo::new(618create_info::<Function>()619.with_args({620let mut _index = 0;621vec![622$(ArgInfo::new::<$Arg>({623_index += 1;624_index - 1625}),)*626]627})628.with_return_info(ReturnInfo::new::<ReturnType>())629)630}631}632633// === (&self, ...) -> &ReturnType === //634impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&Receiver, $($Arg),*) -> &ReturnType> for Function635where636for<'a> &'a Receiver: TypePath + GetOwnership,637$($Arg: TypePath + GetOwnership,)*638for<'a> &'a ReturnType: TypePath + GetOwnership,639Function: for<'a> FnMut(&'a Receiver, $($Arg),*) -> &'a ReturnType,640{641fn function_info() -> FunctionInfo {642FunctionInfo::new(643create_info::<Function>()644.with_args({645let mut _index = 1;646vec![647ArgInfo::new::<&Receiver>(0),648$($crate::func::args::ArgInfo::new::<$Arg>({649_index += 1;650_index - 1651}),)*652]653})654.with_return_info(ReturnInfo::new::<&ReturnType>())655)656}657}658659// === (&mut self, ...) -> &mut ReturnType === //660impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &mut ReturnType> for Function661where662for<'a> &'a mut Receiver: TypePath + GetOwnership,663$($Arg: TypePath + GetOwnership,)*664for<'a> &'a mut ReturnType: TypePath + GetOwnership,665Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a mut ReturnType,666{667fn function_info() -> FunctionInfo {668FunctionInfo::new(669create_info::<Function>()670.with_args({671let mut _index = 1;672vec![673ArgInfo::new::<&mut Receiver>(0),674$(ArgInfo::new::<$Arg>({675_index += 1;676_index - 1677}),)*678]679})680.with_return_info(ReturnInfo::new::<&mut ReturnType>())681)682}683}684685// === (&mut self, ...) -> &ReturnType === //686impl<Receiver, $($Arg,)* ReturnType, Function> TypedFunction<fn(&mut Receiver, $($Arg),*) -> &ReturnType> for Function687where688for<'a> &'a mut Receiver: TypePath + GetOwnership,689$($Arg: TypePath + GetOwnership,)*690for<'a> &'a ReturnType: TypePath + GetOwnership,691Function: for<'a> FnMut(&'a mut Receiver, $($Arg),*) -> &'a ReturnType,692{693fn function_info() -> FunctionInfo {694FunctionInfo::new(695create_info::<Function>()696.with_args({697let mut _index = 1;698vec![699ArgInfo::new::<&mut Receiver>(0),700$(ArgInfo::new::<$Arg>({701_index += 1;702_index - 1703}),)*704]705})706.with_return_info(ReturnInfo::new::<&ReturnType>())707)708}709}710};711}712713all_tuples!(impl_typed_function, 0, 15, Arg, arg);714715/// Helper function for creating [`FunctionInfo`] with the proper name value.716///717/// Names are only given if:718/// - The function is not a closure719/// - The function is not a function pointer720/// - The function is not an anonymous function721///722/// This function relies on the [`type_name`] of `F` to determine this.723/// The following table describes the behavior for different types of functions:724///725/// | Category | `type_name` | `FunctionInfo::name` |726/// | ------------------ | ----------------------- | ----------------------- |727/// | Named function | `foo::bar::baz` | `Some("foo::bar::baz")` |728/// | Closure | `foo::bar::{{closure}}` | `None` |729/// | Anonymous function | `foo::bar::{{closure}}` | `None` |730/// | Function pointer | `fn() -> String` | `None` |731///732/// [`type_name`]: core::any::type_name733fn create_info<F>() -> SignatureInfo {734let name = core::any::type_name::<F>();735736if name.ends_with("{{closure}}") || name.starts_with("fn(") {737SignatureInfo::anonymous()738} else {739SignatureInfo::named(name)740}741}742743#[cfg(test)]744mod tests {745use super::*;746747#[test]748fn should_create_function_info() {749fn add(a: i32, b: i32) -> i32 {750a + b751}752753// Sanity check:754assert_eq!(755core::any::type_name_of_val(&add),756"bevy_reflect::func::info::tests::should_create_function_info::add"757);758759let info = add.get_function_info();760assert_eq!(761info.name().unwrap(),762"bevy_reflect::func::info::tests::should_create_function_info::add"763);764assert_eq!(info.base().arg_count(), 2);765assert_eq!(info.base().args()[0].type_path(), "i32");766assert_eq!(info.base().args()[1].type_path(), "i32");767assert_eq!(info.base().return_info().type_path(), "i32");768}769770#[test]771fn should_create_function_pointer_info() {772fn add(a: i32, b: i32) -> i32 {773a + b774}775776let add = add as fn(i32, i32) -> i32;777778// Sanity check:779assert_eq!(core::any::type_name_of_val(&add), "fn(i32, i32) -> i32");780781let info = add.get_function_info();782assert!(info.name().is_none());783assert_eq!(info.base().arg_count(), 2);784assert_eq!(info.base().args()[0].type_path(), "i32");785assert_eq!(info.base().args()[1].type_path(), "i32");786assert_eq!(info.base().return_info().type_path(), "i32");787}788789#[test]790fn should_create_anonymous_function_info() {791let add = |a: i32, b: i32| a + b;792793// Sanity check:794assert_eq!(795core::any::type_name_of_val(&add),796"bevy_reflect::func::info::tests::should_create_anonymous_function_info::{{closure}}"797);798799let info = add.get_function_info();800assert!(info.name().is_none());801assert_eq!(info.base().arg_count(), 2);802assert_eq!(info.base().args()[0].type_path(), "i32");803assert_eq!(info.base().args()[1].type_path(), "i32");804assert_eq!(info.base().return_info().type_path(), "i32");805}806807#[test]808fn should_create_closure_info() {809let mut total = 0;810let add = |a: i32, b: i32| total = a + b;811812// Sanity check:813assert_eq!(814core::any::type_name_of_val(&add),815"bevy_reflect::func::info::tests::should_create_closure_info::{{closure}}"816);817818let info = add.get_function_info();819assert!(info.name().is_none());820assert_eq!(info.base().arg_count(), 2);821assert_eq!(info.base().args()[0].type_path(), "i32");822assert_eq!(info.base().args()[1].type_path(), "i32");823assert_eq!(info.base().return_info().type_path(), "()");824}825826#[test]827fn should_pretty_print_info() {828// fn add(a: i32, b: i32) -> i32 {829// a + b830// }831//832// let info = add.get_function_info().with_name("add");833//834// let pretty = info.pretty_printer();835// assert_eq!(format!("{:?}", pretty), "(_: i32, _: i32) -> i32");836//837// let pretty = info.pretty_printer().include_fn_token();838// assert_eq!(format!("{:?}", pretty), "fn(_: i32, _: i32) -> i32");839//840// let pretty = info.pretty_printer().include_name();841// assert_eq!(format!("{:?}", pretty), "add(_: i32, _: i32) -> i32");842//843// let pretty = info.pretty_printer().include_fn_token().include_name();844// assert_eq!(format!("{:?}", pretty), "fn add(_: i32, _: i32) -> i32");845}846}847848849