bevy_reflect/func/function.rs
1use crate::{
2 func::{ArgList, DynamicFunction, FunctionInfo, FunctionResult},
3 PartialReflect,
4};
5use alloc::borrow::Cow;
6use core::fmt::Debug;
7
8/// A trait used to power [function-like] operations via [reflection].
9///
10/// This trait allows types to be called like regular functions
11/// with [`Reflect`]-based [arguments] and return values.
12///
13/// By default, this trait is currently only implemented for [`DynamicFunction`],
14/// however, it is possible to implement this trait for custom function-like types.
15///
16/// # Example
17///
18/// ```
19/// # use bevy_reflect::func::{IntoFunction, ArgList, Function};
20/// fn add(a: i32, b: i32) -> i32 {
21/// a + b
22/// }
23///
24/// let func: Box<dyn Function> = Box::new(add.into_function());
25/// let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
26/// let value = func.reflect_call(args).unwrap().unwrap_owned();
27/// assert_eq!(value.try_take::<i32>().unwrap(), 100);
28/// ```
29///
30/// [function-like]: crate::func
31/// [reflection]: crate::Reflect
32/// [`Reflect`]: crate::Reflect
33/// [arguments]: crate::func::args
34/// [`DynamicFunction`]: crate::func::DynamicFunction
35pub trait Function: PartialReflect + Debug {
36 /// The name of the function, if any.
37 ///
38 /// For [`DynamicFunctions`] created using [`IntoFunction`],
39 /// the default name will always be the full path to the function as returned by [`std::any::type_name`],
40 /// unless the function is a closure, anonymous function, or function pointer,
41 /// in which case the name will be `None`.
42 ///
43 /// [`DynamicFunctions`]: crate::func::DynamicFunction
44 /// [`IntoFunction`]: crate::func::IntoFunction
45 fn name(&self) -> Option<&Cow<'static, str>> {
46 self.info().name()
47 }
48
49 /// The number of arguments this function accepts.
50 fn arg_count(&self) -> usize {
51 self.info().arg_count()
52 }
53
54 /// The [`FunctionInfo`] for this function.
55 fn info(&self) -> &FunctionInfo;
56
57 /// Call this function with the given arguments.
58 fn reflect_call<'a>(&self, args: ArgList<'a>) -> FunctionResult<'a>;
59
60 /// Clone this function into a [`DynamicFunction`].
61 fn clone_dynamic(&self) -> DynamicFunction<'static>;
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use crate::func::IntoFunction;
68
69 #[test]
70 fn should_call_dyn_function() {
71 fn add(a: i32, b: i32) -> i32 {
72 a + b
73 }
74
75 let func: Box<dyn Function> = Box::new(add.into_function());
76 let args = ArgList::new().push_owned(25_i32).push_owned(75_i32);
77 let value = func.reflect_call(args).unwrap().unwrap_owned();
78 assert_eq!(value.try_take::<i32>().unwrap(), 100);
79 }
80}