From 0eb2398a26d43d0f4c9759776bef154c255951e6 Mon Sep 17 00:00:00 2001 From: Gino Valente Date: Fri, 6 Sep 2024 14:27:05 -0700 Subject: [PATCH] Updated function_reflection example --- examples/reflection/function_reflection.rs | 47 +++++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/examples/reflection/function_reflection.rs b/examples/reflection/function_reflection.rs index c37db7941a..0c34f6f5ba 100644 --- a/examples/reflection/function_reflection.rs +++ b/examples/reflection/function_reflection.rs @@ -83,7 +83,50 @@ fn main() { dbg!(closure.call_once(args).unwrap()); assert_eq!(count, 5); - // As stated before, this works for many kinds of simple functions. + // Generic functions can also be converted into a `DynamicFunction`, + // however, they will need to be manually monomorphized first. + fn stringify(value: T) -> String { + value.to_string() + } + + // We have to manually specify the concrete generic type we want to use. + let function = stringify::.into_function(); + + let args = ArgList::new().push_owned(123_i32); + let return_value = function.call(args).unwrap(); + let value: Box = return_value.unwrap_owned(); + assert_eq!(value.try_take::().unwrap(), "123"); + + // To make things a little easier, we can also "overload" functions. + // This makes it so that a single `DynamicFunction` can represent multiple functions, + // and the correct one is chosen based on the types of the arguments. + // Each function overload must have a unique argument signature. + let function = stringify:: + .into_function() + .with_overload(stringify::); + + // Now our `function` accepts both `i32` and `f32` arguments. + let args = ArgList::new().push_owned(1.23_f32); + let return_value = function.call(args).unwrap(); + let value: Box = return_value.unwrap_owned(); + assert_eq!(value.try_take::().unwrap(), "1.23"); + + // Function overloading even allows us to have a variable number of arguments. + let function = (|| 0) + .into_function() + .with_overload(|a: i32| a) + .with_overload(|a: i32, b: i32| a + b) + .with_overload(|a: i32, b: i32, c: i32| a + b + c); + + let args = ArgList::new() + .push_owned(1_i32) + .push_owned(2_i32) + .push_owned(3_i32); + let return_value = function.call(args).unwrap(); + let value: Box = return_value.unwrap_owned(); + assert_eq!(value.try_take::().unwrap(), 6); + + // As stated earlier, `IntoFunction` works for many kinds of simple functions. // Functions with non-reflectable arguments or return values may not be able to be converted. // Generic functions are also not supported (unless manually monomorphized like `foo::.into_function()`). // Additionally, the lifetime of the return value is tied to the lifetime of the first argument. @@ -118,7 +161,7 @@ fn main() { let value: &dyn PartialReflect = return_value.unwrap_ref(); assert_eq!(value.try_downcast_ref::().unwrap(), "Hello, world!"); - // Lastly, for more complex use cases, you can always create a custom `DynamicFunction` manually. + // For more complex use cases, you can always create a custom `DynamicFunction` manually. // This is useful for functions that can't be converted via the `IntoFunction` trait. // For example, this function doesn't implement `IntoFunction` due to the fact that // the lifetime of the return value is not tied to the lifetime of the first argument.