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 `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

View File

@ -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<T> From<EvalAltResult> for Result<T, Box<EvalAltResult>> {
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.
///
/// # 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.
///

View File

@ -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),
})

View File

@ -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<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 `()`.
/// 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)
}
}

View File

@ -146,7 +146,7 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
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])
},
);

View File

@ -17,7 +17,7 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|context, args| {
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| {
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(
"do_stuff",
|context: NativeCallContext, callback: rhai::FnPtr| {
callback.call_dynamic(&context, None, [])
|context: NativeCallContext, callback: rhai::FnPtr| -> Result<INT, _> {
callback.call_within_context(&context, ())
},
);