Add FnPtr::call_within_context.

This commit is contained in:
Stephen Chung 2021-11-29 12:43:59 +08:00
parent 0ab86ac623
commit ba0a6c667e
8 changed files with 106 additions and 39 deletions

View File

@ -13,7 +13,7 @@ Enhancements
------------ ------------
* Added `into_array` and `into_typed_array` for `Dynamic`. * 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 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`. * `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::merge_filtered` and `AST::combine_filtered` are no longer exported under `no_function`.
* `AST::new` and `AST::new_with_source` are moved under `internals`. * `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 Version 1.2.1

View File

@ -1,7 +1,8 @@
//! Module containing all deprecated API that will be removed in the next major version. //! Module containing all deprecated API that will be removed in the next major version.
use crate::{ use crate::{
Dynamic, Engine, EvalAltResult, ImmutableString, NativeCallContext, RhaiResult, Scope, AST, Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, RhaiResult, Scope,
AST,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
@ -256,3 +257,39 @@ impl<T> From<EvalAltResult> for Result<T, Box<EvalAltResult>> {
Err(err.into()) 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)
}
}

View File

@ -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. /// 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], /// 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. /// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
/// ///

View File

@ -261,12 +261,12 @@ mod array_functions {
for (i, item) in array.iter().enumerate() { for (i, item) in array.iter().enumerate() {
ar.push( ar.push(
mapper mapper
.call_dynamic(&ctx, None, [item.clone()]) .call_raw(&ctx, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(mapper.fn_name()) => 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), _ => Err(err),
}) })
@ -306,12 +306,12 @@ mod array_functions {
for (i, item) in array.iter().enumerate() { for (i, item) in array.iter().enumerate() {
if filter if filter
.call_dynamic(&ctx, None, [item.clone()]) .call_raw(&ctx, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })
@ -478,12 +478,12 @@ mod array_functions {
for (i, item) in array.iter().enumerate().skip(start) { for (i, item) in array.iter().enumerate().skip(start) {
if filter if filter
.call_dynamic(&ctx, None, [item.clone()]) .call_raw(&ctx, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })
@ -525,12 +525,12 @@ mod array_functions {
for (i, item) in array.iter().enumerate() { for (i, item) in array.iter().enumerate() {
if filter if filter
.call_dynamic(&ctx, None, [item.clone()]) .call_raw(&ctx, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })
@ -571,12 +571,12 @@ mod array_functions {
for (i, item) in array.iter().enumerate() { for (i, item) in array.iter().enumerate() {
if !filter if !filter
.call_dynamic(&ctx, None, [item.clone()]) .call_raw(&ctx, None, [item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })
@ -621,7 +621,7 @@ mod array_functions {
array.dedup_by(|x, y| { array.dedup_by(|x, y| {
comparer comparer
.call_dynamic(&ctx, None, [x.clone(), y.clone()]) .call_raw(&ctx, None, [x.clone(), y.clone()])
.unwrap_or_else(|_| Dynamic::FALSE) .unwrap_or_else(|_| Dynamic::FALSE)
.as_bool() .as_bool()
.unwrap_or(false) .unwrap_or(false)
@ -670,12 +670,12 @@ mod array_functions {
let item = item.clone(); let item = item.clone();
result = reducer result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()]) .call_raw(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) => 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), _ => Err(err),
}) })
@ -734,16 +734,12 @@ mod array_functions {
let item = item.clone(); let item = item.clone();
result = reducer result = reducer
.call_dynamic(&ctx, None, [result.clone(), item.clone()]) .call_raw(&ctx, None, [result.clone(), item.clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(reducer.fn_name()) => if fn_sig.starts_with(reducer.fn_name()) =>
{ {
reducer.call_dynamic( reducer.call_raw(&ctx, None, [result, item, ((len - 1 - i) as INT).into()])
&ctx,
None,
[result, item, ((len - 1 - i) as INT).into()],
)
} }
_ => Err(err), _ => Err(err),
}) })
@ -788,7 +784,7 @@ mod array_functions {
array.sort_by(|x, y| { array.sort_by(|x, y| {
comparer comparer
.call_dynamic(&ctx, None, [x.clone(), y.clone()]) .call_raw(&ctx, None, [x.clone(), y.clone()])
.ok() .ok()
.and_then(|v| v.as_int().ok()) .and_then(|v| v.as_int().ok())
.map(|v| match v { .map(|v| match v {
@ -891,12 +887,12 @@ mod array_functions {
while x < array.len() { while x < array.len() {
if filter if filter
.call_dynamic(&ctx, None, [array[x].clone()]) .call_raw(&ctx, None, [array[x].clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })
@ -973,12 +969,12 @@ mod array_functions {
while x < array.len() { while x < array.len() {
if !filter if !filter
.call_dynamic(&ctx, None, [array[x].clone()]) .call_raw(&ctx, None, [array[x].clone()])
.or_else(|err| match *err { .or_else(|err| match *err {
EvalAltResult::ErrorFunctionNotFound(fn_sig, _) EvalAltResult::ErrorFunctionNotFound(fn_sig, _)
if fn_sig.starts_with(filter.fn_name()) => 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), _ => Err(err),
}) })

View File

@ -101,9 +101,8 @@ impl FnPtr {
/// Call the function pointer with curried arguments (if any). /// Call the function pointer with curried arguments (if any).
/// The function may be script-defined (not available under `no_function`) or native Rust. /// 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 /// This method is intended for calling a function pointer directly, possibly on another [`Engine`].
/// function as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the /// Therefore, the [`AST`] is _NOT_ evaluated before calling the function.
/// function.
/// ///
/// # Example /// # Example
/// ///
@ -153,7 +152,7 @@ impl FnPtr {
#[allow(deprecated)] #[allow(deprecated)]
let ctx = NativeCallContext::new(engine, self.fn_name(), lib); 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()); 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 /// 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 as an argument. Therefore, the [`AST`] is _NOT_ evaluated before calling the
/// function. /// function.
#[inline]
pub fn call_within_context<T: Variant + Clone>(
&self,
context: &NativeCallContext,
args: impl FuncArgs,
) -> Result<T, Box<EvalAltResult>> {
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::<T>()).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 `()`. /// All the arguments are _consumed_, meaning that they're replaced by `()`.
/// This is to avoid unnecessarily cloning the arguments. /// This is to avoid unnecessarily cloning the arguments.
/// Do not use the arguments after this call. If they are needed afterwards, /// Do not use the arguments after this call. If they are needed afterwards,
/// clone them _before_ calling this function. /// clone them _before_ calling this function.
#[inline] #[inline]
pub fn call_dynamic( pub fn call_raw(
&self, &self,
ctx: &NativeCallContext, context: &NativeCallContext,
this_ptr: Option<&mut Dynamic>, this_ptr: Option<&mut Dynamic>,
arg_values: impl AsMut<[Dynamic]>, arg_values: impl AsMut<[Dynamic]>,
) -> RhaiResult { ) -> RhaiResult {
@ -205,7 +236,7 @@ impl FnPtr {
} }
args.extend(arg_values.iter_mut()); 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)
} }
} }

View File

@ -146,7 +146,7 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
let value = args[2].clone(); let value = args[2].clone();
let this_ptr = args.get_mut(0).unwrap(); let this_ptr = args.get_mut(0).unwrap();
fp.call_dynamic(&context, Some(this_ptr), [value]) fp.call_raw(&context, Some(this_ptr), [value])
}, },
); );

View File

@ -17,7 +17,7 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()], &[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|context, args| { |context, args| {
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>(); let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>();
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<EvalAltResult>> {
|context, args| { |context, args| {
let func = take(args[1]).cast::<FnPtr>(); let func = take(args[1]).cast::<FnPtr>();
func.call_dynamic(&context, None, []) func.call_raw(&context, None, [])
}, },
); );

View File

@ -98,8 +98,8 @@ fn test_functions_global_module() -> Result<(), Box<EvalAltResult>> {
engine.register_result_fn( engine.register_result_fn(
"do_stuff", "do_stuff",
|context: NativeCallContext, callback: rhai::FnPtr| { |context: NativeCallContext, callback: rhai::FnPtr| -> Result<INT, _> {
callback.call_dynamic(&context, None, []) callback.call_within_context(&context, ())
}, },
); );