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