From ba0a6c667e4832ca50e1f77fff4e714ac0970e48 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 29 Nov 2021 12:43:59 +0800 Subject: [PATCH] Add FnPtr::call_within_context. --- CHANGELOG.md | 3 ++- src/api/deprecated.rs | 39 +++++++++++++++++++++++++++++- src/api/register.rs | 2 ++ src/packages/array_basic.rs | 44 ++++++++++++++++------------------ src/types/fn_ptr.rs | 47 ++++++++++++++++++++++++++++++------- tests/call_fn.rs | 2 +- tests/closures.rs | 4 ++-- tests/functions.rs | 4 ++-- 8 files changed, 106 insertions(+), 39 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d901fa5..1108516a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ Enhancements ------------ * Added `into_array` and `into_typed_array` for `Dynamic`. -* Added `FnPtr::call` to simplify calling a function pointer. +* Added `FnPtr::call` and `FnPtr::call_within_context` to simplify calling a function pointer. Deprecated and Gated API's -------------------------- @@ -21,6 +21,7 @@ Deprecated and Gated API's * `NativeCallContext::new` is deprecated because it is simpler to call a function pointer via `FnPtr::call`. * `AST::merge_filtered` and `AST::combine_filtered` are no longer exported under `no_function`. * `AST::new` and `AST::new_with_source` are moved under `internals`. +* `FnPtr::call_dynamic` is deprecated in favor of `FnPtr::call_raw`. Version 1.2.1 diff --git a/src/api/deprecated.rs b/src/api/deprecated.rs index 0673fe52..1d0f4a64 100644 --- a/src/api/deprecated.rs +++ b/src/api/deprecated.rs @@ -1,7 +1,8 @@ //! Module containing all deprecated API that will be removed in the next major version. use crate::{ - Dynamic, Engine, EvalAltResult, ImmutableString, NativeCallContext, RhaiResult, Scope, AST, + Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, RhaiResult, Scope, + AST, }; #[cfg(feature = "no_std")] @@ -256,3 +257,39 @@ impl From for Result> { Err(err.into()) } } + +impl FnPtr { + /// Call the function pointer with curried arguments (if any). + /// The function may be script-defined (not available under `no_function`) or native Rust. + /// + /// This method is intended for calling a function pointer that is passed into a native Rust + /// function as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the + /// function. + /// + /// # Deprecated + /// + /// This method is deprecated. Use [`call_within_context`][FnPtr::call_within_context] or + /// [`call_raw`][FnPtr::call_raw] instead. + /// + /// This method will be removed in the next major version. + /// + /// # WARNING + /// + /// All the arguments are _consumed_, meaning that they're replaced by `()`. + /// This is to avoid unnecessarily cloning the arguments. + /// Do not use the arguments after this call. If they are needed afterwards, + /// clone them _before_ calling this function. + #[deprecated( + since = "1.3.0", + note = "use `call_within_context` or `call_raw` instead" + )] + #[inline(always)] + pub fn call_dynamic( + &self, + context: &NativeCallContext, + this_ptr: Option<&mut Dynamic>, + arg_values: impl AsMut<[Dynamic]>, + ) -> RhaiResult { + self.call_raw(context, this_ptr, arg_values) + } +} diff --git a/src/api/register.rs b/src/api/register.rs index 58135f10..85288e00 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -154,6 +154,8 @@ impl Engine { /// /// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s indicating the actual types of the parameters. /// + /// # Arguments + /// /// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic], /// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s. /// diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index fd847129..1b1f55dd 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -261,12 +261,12 @@ mod array_functions { for (i, item) in array.iter().enumerate() { ar.push( mapper - .call_dynamic(&ctx, None, [item.clone()]) + .call_raw(&ctx, None, [item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(mapper.fn_name()) => { - mapper.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()]) + mapper.call_raw(&ctx, None, [item.clone(), (i as INT).into()]) } _ => Err(err), }) @@ -306,12 +306,12 @@ mod array_functions { for (i, item) in array.iter().enumerate() { if filter - .call_dynamic(&ctx, None, [item.clone()]) + .call_raw(&ctx, None, [item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()]) } _ => Err(err), }) @@ -478,12 +478,12 @@ mod array_functions { for (i, item) in array.iter().enumerate().skip(start) { if filter - .call_dynamic(&ctx, None, [item.clone()]) + .call_raw(&ctx, None, [item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()]) } _ => Err(err), }) @@ -525,12 +525,12 @@ mod array_functions { for (i, item) in array.iter().enumerate() { if filter - .call_dynamic(&ctx, None, [item.clone()]) + .call_raw(&ctx, None, [item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()]) } _ => Err(err), }) @@ -571,12 +571,12 @@ mod array_functions { for (i, item) in array.iter().enumerate() { if !filter - .call_dynamic(&ctx, None, [item.clone()]) + .call_raw(&ctx, None, [item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [item.clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [item.clone(), (i as INT).into()]) } _ => Err(err), }) @@ -621,7 +621,7 @@ mod array_functions { array.dedup_by(|x, y| { comparer - .call_dynamic(&ctx, None, [x.clone(), y.clone()]) + .call_raw(&ctx, None, [x.clone(), y.clone()]) .unwrap_or_else(|_| Dynamic::FALSE) .as_bool() .unwrap_or(false) @@ -670,12 +670,12 @@ mod array_functions { let item = item.clone(); result = reducer - .call_dynamic(&ctx, None, [result.clone(), item.clone()]) + .call_raw(&ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(reducer.fn_name()) => { - reducer.call_dynamic(&ctx, None, [result, item, (i as INT).into()]) + reducer.call_raw(&ctx, None, [result, item, (i as INT).into()]) } _ => Err(err), }) @@ -734,16 +734,12 @@ mod array_functions { let item = item.clone(); result = reducer - .call_dynamic(&ctx, None, [result.clone(), item.clone()]) + .call_raw(&ctx, None, [result.clone(), item.clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(reducer.fn_name()) => { - reducer.call_dynamic( - &ctx, - None, - [result, item, ((len - 1 - i) as INT).into()], - ) + reducer.call_raw(&ctx, None, [result, item, ((len - 1 - i) as INT).into()]) } _ => Err(err), }) @@ -788,7 +784,7 @@ mod array_functions { array.sort_by(|x, y| { comparer - .call_dynamic(&ctx, None, [x.clone(), y.clone()]) + .call_raw(&ctx, None, [x.clone(), y.clone()]) .ok() .and_then(|v| v.as_int().ok()) .map(|v| match v { @@ -891,12 +887,12 @@ mod array_functions { while x < array.len() { if filter - .call_dynamic(&ctx, None, [array[x].clone()]) + .call_raw(&ctx, None, [array[x].clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [array[x].clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()]) } _ => Err(err), }) @@ -973,12 +969,12 @@ mod array_functions { while x < array.len() { if !filter - .call_dynamic(&ctx, None, [array[x].clone()]) + .call_raw(&ctx, None, [array[x].clone()]) .or_else(|err| match *err { EvalAltResult::ErrorFunctionNotFound(fn_sig, _) if fn_sig.starts_with(filter.fn_name()) => { - filter.call_dynamic(&ctx, None, [array[x].clone(), (i as INT).into()]) + filter.call_raw(&ctx, None, [array[x].clone(), (i as INT).into()]) } _ => Err(err), }) diff --git a/src/types/fn_ptr.rs b/src/types/fn_ptr.rs index 835935cb..e0476717 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -101,9 +101,8 @@ impl FnPtr { /// Call the function pointer with curried arguments (if any). /// The function may be script-defined (not available under `no_function`) or native Rust. /// - /// This method is intended for calling a function pointer that is passed into a native Rust - /// function as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the - /// function. + /// This method is intended for calling a function pointer directly, possibly on another [`Engine`]. + /// Therefore, the [`AST`] is _NOT_ evaluated before calling the function. /// /// # Example /// @@ -153,7 +152,7 @@ impl FnPtr { #[allow(deprecated)] let ctx = NativeCallContext::new(engine, self.fn_name(), lib); - let result = self.call_dynamic(&ctx, None, arg_values)?; + let result = self.call_raw(&ctx, None, arg_values)?; let typ = engine.map_type_name(result.type_name()); @@ -172,17 +171,49 @@ impl FnPtr { /// This method is intended for calling a function pointer that is passed into a native Rust /// function as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the /// function. + #[inline] + pub fn call_within_context( + &self, + context: &NativeCallContext, + args: impl FuncArgs, + ) -> Result> { + let mut arg_values = crate::StaticVec::new_const(); + args.parse(&mut arg_values); + + let result = self.call_raw(&context, None, arg_values)?; + + let typ = context.engine().map_type_name(result.type_name()); + + result.try_cast().ok_or_else(|| { + EvalAltResult::ErrorMismatchOutputType( + context.engine().map_type_name(type_name::()).into(), + typ.into(), + Position::NONE, + ) + .into() + }) + } + /// Call the function pointer with curried arguments (if any). + /// The function may be script-defined (not available under `no_function`) or native Rust. /// - /// # WARNING + /// This method is intended for calling a function pointer that is passed into a native Rust + /// function as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the + /// function. + /// + /// # WARNING - Low Level API + /// + /// This function is very low level. + /// + /// # Arguments /// /// All the arguments are _consumed_, meaning that they're replaced by `()`. /// This is to avoid unnecessarily cloning the arguments. /// Do not use the arguments after this call. If they are needed afterwards, /// clone them _before_ calling this function. #[inline] - pub fn call_dynamic( + pub fn call_raw( &self, - ctx: &NativeCallContext, + context: &NativeCallContext, this_ptr: Option<&mut Dynamic>, arg_values: impl AsMut<[Dynamic]>, ) -> RhaiResult { @@ -205,7 +236,7 @@ impl FnPtr { } args.extend(arg_values.iter_mut()); - ctx.call_fn_raw(self.fn_name(), is_method, is_method, &mut args) + context.call_fn_raw(self.fn_name(), is_method, is_method, &mut args) } } diff --git a/tests/call_fn.rs b/tests/call_fn.rs index 4a2d776f..2542a0e4 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -146,7 +146,7 @@ fn test_fn_ptr_raw() -> Result<(), Box> { let value = args[2].clone(); let this_ptr = args.get_mut(0).unwrap(); - fp.call_dynamic(&context, Some(this_ptr), [value]) + fp.call_raw(&context, Some(this_ptr), [value]) }, ); diff --git a/tests/closures.rs b/tests/closures.rs index 5213bf3f..84b270d7 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -17,7 +17,7 @@ fn test_fn_ptr_curry_call() -> Result<(), Box> { &[TypeId::of::(), TypeId::of::()], |context, args| { let fn_ptr = std::mem::take(args[0]).cast::(); - fn_ptr.call_dynamic(&context, None, [std::mem::take(args[1])]) + fn_ptr.call_raw(&context, None, [std::mem::take(args[1])]) }, ); @@ -155,7 +155,7 @@ fn test_closures() -> Result<(), Box> { |context, args| { let func = take(args[1]).cast::(); - func.call_dynamic(&context, None, []) + func.call_raw(&context, None, []) }, ); diff --git a/tests/functions.rs b/tests/functions.rs index ba586cee..491f9559 100644 --- a/tests/functions.rs +++ b/tests/functions.rs @@ -98,8 +98,8 @@ fn test_functions_global_module() -> Result<(), Box> { engine.register_result_fn( "do_stuff", - |context: NativeCallContext, callback: rhai::FnPtr| { - callback.call_dynamic(&context, None, []) + |context: NativeCallContext, callback: rhai::FnPtr| -> Result { + callback.call_within_context(&context, ()) }, );