Encapsulate register_fn_raw parameters into NativeCallContext.
This commit is contained in:
parent
58c820785b
commit
82e6dd446a
@ -10,6 +10,7 @@ Breaking changes
|
|||||||
|
|
||||||
* `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`.
|
* `EvalAltResult::ErrorReadingScriptFile` is removed in favor of the new `EvalAltResult::ErrorSystem`.
|
||||||
* `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`.
|
* `EvalAltResult::ErrorLoopBreak` is renamed to `EvalAltResult::LoopBreak`.
|
||||||
|
* `Engine::register_raw_fn` function signature has changed.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
|
|
||||||
|
@ -17,10 +17,11 @@ Built-in methods
|
|||||||
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
||||||
using a [raw `Engine`]) operate on function pointers:
|
using a [raw `Engine`]) operate on function pointers:
|
||||||
|
|
||||||
| Function | Parameter(s) | Description |
|
| Function | Parameter(s) | Description |
|
||||||
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
| ---------------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||||
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
|
| `is_anonymous` method and property | _none_ | does the function pointer refer to an [anonymous function]? |
|
||||||
|
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
|
||||||
|
|
||||||
|
|
||||||
Examples
|
Examples
|
||||||
@ -186,16 +187,15 @@ must be used to register the function.
|
|||||||
|
|
||||||
Essentially, use the low-level `Engine::register_raw_fn` method to register the function.
|
Essentially, use the low-level `Engine::register_raw_fn` method to register the function.
|
||||||
`FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the
|
`FnPtr::call_dynamic` is used to actually call the function pointer, passing to it the
|
||||||
current scripting [`Engine`], collection of script-defined functions, the `this` pointer,
|
current _native call context_, the `this` pointer, and other necessary arguments.
|
||||||
and other necessary arguments.
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext};
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Define Rust function in required low-level API signature
|
// Define Rust function in required low-level API signature
|
||||||
fn call_fn_ptr_with_value(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic])
|
fn call_fn_ptr_with_value(context: NativeCallContext, args: &mut [&mut Dynamic])
|
||||||
-> Result<Dynamic, Box<EvalAltResult>>
|
-> Result<Dynamic, Box<EvalAltResult>>
|
||||||
{
|
{
|
||||||
// 'args' is guaranteed to contain enough arguments of the correct types
|
// 'args' is guaranteed to contain enough arguments of the correct types
|
||||||
@ -205,7 +205,7 @@ fn call_fn_ptr_with_value(engine: &Engine, lib: &Module, args: &mut [&mut Dynami
|
|||||||
|
|
||||||
// Use 'FnPtr::call_dynamic' to call the function pointer.
|
// Use 'FnPtr::call_dynamic' to call the function pointer.
|
||||||
// Beware, private script-defined functions will not be found.
|
// Beware, private script-defined functions will not be found.
|
||||||
fp.call_dynamic(engine, lib, Some(this_ptr), [value])
|
fp.call_dynamic(context, Some(this_ptr), [value])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register a Rust function using the low-level API
|
// Register a Rust function using the low-level API
|
||||||
@ -218,3 +218,43 @@ engine.register_raw_fn("super_call",
|
|||||||
call_fn_ptr_with_value
|
call_fn_ptr_with_value
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
`NativeCallContext`
|
||||||
|
------------------
|
||||||
|
|
||||||
|
`FnPtr::call_dynamic` takes a parameter of type `NativeCallContext` which holds the _native call context_
|
||||||
|
of the particular call to a registered Rust function.
|
||||||
|
|
||||||
|
This type is normally provided by the [`Engine`] (e.g. when using `Engine::register_fn_raw`(../rust/register-raw.md)).
|
||||||
|
However, it may also be manually constructed from a tuple:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rhai::{Engine, FnPtr};
|
||||||
|
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
// Compile script to AST
|
||||||
|
let mut ast = engine.compile(
|
||||||
|
r#"
|
||||||
|
let test = "hello";
|
||||||
|
|x| test + x // this creates an closure
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Save the closure together with captured variables
|
||||||
|
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
||||||
|
|
||||||
|
// Get rid of the script, retaining only functions
|
||||||
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
|
// Create native call context via a tuple containing the Engine and the
|
||||||
|
// set of script-defined functions (within the AST)
|
||||||
|
let context = (&engine, ast.as_ref()).into();
|
||||||
|
|
||||||
|
// 'f' captures: the engine, the AST, and the closure
|
||||||
|
let f = move |x: i64| fn_ptr.call_dynamic(context, None, [x.into()]);
|
||||||
|
|
||||||
|
// 'f' can be called like a normal function
|
||||||
|
let result = f(42)?;
|
||||||
|
```
|
||||||
|
@ -18,8 +18,9 @@ The `Engine::register_raw_fn` method is marked _volatile_, meaning that it may b
|
|||||||
|
|
||||||
If this is acceptable, then using this method to register a Rust function opens up more opportunities.
|
If this is acceptable, then using this method to register a Rust function opens up more opportunities.
|
||||||
|
|
||||||
In particular, a reference to the current `Engine` instance is passed as an argument so the Rust function
|
In particular, a the current _native call context_ (in form of the `NativeCallContext` type) is passed as an argument.
|
||||||
can also use `Engine` facilities (like evaluating a script).
|
`NativeCallContext` exposes the current [`Engine`], among others, so the Rust function can also use [`Engine`] facilities
|
||||||
|
(such as evaluating a script).
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
engine.register_raw_fn(
|
engine.register_raw_fn(
|
||||||
@ -28,7 +29,7 @@ engine.register_raw_fn(
|
|||||||
std::any::TypeId::of::<i64>(), // type of first parameter
|
std::any::TypeId::of::<i64>(), // type of first parameter
|
||||||
std::any::TypeId::of::<i64>() // type of second parameter
|
std::any::TypeId::of::<i64>() // type of second parameter
|
||||||
],
|
],
|
||||||
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| { // fixed function signature
|
|context, args| { // fixed function signature
|
||||||
// Arguments are guaranteed to be correct in number and of the correct types.
|
// Arguments are guaranteed to be correct in number and of the correct types.
|
||||||
|
|
||||||
// But remember this is Rust, so you can keep only one mutable reference at any one time!
|
// But remember this is Rust, so you can keep only one mutable reference at any one time!
|
||||||
@ -59,17 +60,19 @@ Function Signature
|
|||||||
|
|
||||||
The function signature passed to `Engine::register_raw_fn` takes the following form:
|
The function signature passed to `Engine::register_raw_fn` takes the following form:
|
||||||
|
|
||||||
> `Fn(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic])`
|
> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>> + 'static`
|
||||||
> `-> Result<T, Box<EvalAltResult>> + 'static`
|
|
||||||
|
|
||||||
where:
|
where:
|
||||||
|
|
||||||
* `T: Variant + Clone` - return type of the function.
|
* `T: Variant + Clone` - return type of the function.
|
||||||
|
|
||||||
* `engine: &Engine` - the current [`Engine`], with all configurations and settings.
|
* `context: NativeCallContext` - the current _native call context_, which exposes the following:
|
||||||
|
|
||||||
* `lib: &Module` - the current global library of script-defined functions, as a [`Module`].
|
* `context.engine(): &Engine` - the current [`Engine`], with all configurations and settings.
|
||||||
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`].
|
This is sometimes useful for calling a script-defined function within the same evaluation context
|
||||||
|
using [`Engine::call_fn`][`call_fn`].
|
||||||
|
|
||||||
|
* `context.namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
|
||||||
|
|
||||||
* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values.
|
* `args: &mut [&mut Dynamic]` - a slice containing `&mut` references to [`Dynamic`] values.
|
||||||
The slice is guaranteed to contain enough arguments _of the correct types_.
|
The slice is guaranteed to contain enough arguments _of the correct types_.
|
||||||
@ -106,7 +109,7 @@ then calls it within the same [`Engine`]. This way, a _callback_ function can b
|
|||||||
to a native Rust function.
|
to a native Rust function.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
use rhai::{Engine, FnPtr};
|
||||||
|
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
@ -118,7 +121,7 @@ engine.register_raw_fn(
|
|||||||
std::any::TypeId::of::<FnPtr>(),
|
std::any::TypeId::of::<FnPtr>(),
|
||||||
std::any::TypeId::of::<i64>(),
|
std::any::TypeId::of::<i64>(),
|
||||||
],
|
],
|
||||||
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
|
|context, args| {
|
||||||
// 'args' is guaranteed to contain enough arguments of the correct types
|
// 'args' is guaranteed to contain enough arguments of the correct types
|
||||||
|
|
||||||
let fp = std::mem::take(args[1]).cast::<FnPtr>(); // 2nd argument - function pointer
|
let fp = std::mem::take(args[1]).cast::<FnPtr>(); // 2nd argument - function pointer
|
||||||
@ -127,7 +130,7 @@ engine.register_raw_fn(
|
|||||||
|
|
||||||
// Use 'FnPtr::call_dynamic' to call the function pointer.
|
// Use 'FnPtr::call_dynamic' to call the function pointer.
|
||||||
// Beware, private script-defined functions will not be found.
|
// Beware, private script-defined functions will not be found.
|
||||||
fp.call_dynamic(engine, lib, Some(this_ptr), [value])
|
fp.call_dynamic(context, Some(this_ptr), [value])
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
13
src/api.rs
13
src/api.rs
@ -3,8 +3,7 @@
|
|||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{Engine, EvalContext, Imports, State};
|
use crate::engine::{Engine, EvalContext, Imports, State};
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_native::SendSync;
|
use crate::fn_native::{NativeCallContext, SendSync};
|
||||||
use crate::module::{FuncReturn, Module};
|
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::parser::AST;
|
use crate::parser::AST;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -28,7 +27,7 @@ use crate::{
|
|||||||
use crate::fn_register::{RegisterFn, RegisterResultFn};
|
use crate::fn_register::{RegisterFn, RegisterResultFn};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::{fn_args::FuncArgs, fn_call::ensure_no_data_race, StaticVec};
|
use crate::{fn_args::FuncArgs, fn_call::ensure_no_data_race, module::Module, StaticVec};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_optimize"))]
|
#[cfg(not(feature = "no_optimize"))]
|
||||||
use crate::optimize::optimize_into_ast;
|
use crate::optimize::optimize_into_ast;
|
||||||
@ -69,7 +68,9 @@ impl Engine {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: &str,
|
name: &str,
|
||||||
arg_types: &[TypeId],
|
arg_types: &[TypeId],
|
||||||
func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.global_module.set_raw_fn(name, arg_types, func);
|
self.global_module.set_raw_fn(name, arg_types, func);
|
||||||
self
|
self
|
||||||
@ -1622,7 +1623,7 @@ impl Engine {
|
|||||||
name: &str,
|
name: &str,
|
||||||
mut this_ptr: Option<&mut Dynamic>,
|
mut this_ptr: Option<&mut Dynamic>,
|
||||||
mut arg_values: impl AsMut<[Dynamic]>,
|
mut arg_values: impl AsMut<[Dynamic]>,
|
||||||
) -> FuncReturn<Dynamic> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
let mut args: StaticVec<_> = arg_values.as_mut().iter_mut().collect();
|
||||||
|
|
||||||
self.call_fn_dynamic_raw(scope, lib.as_ref(), name, &mut this_ptr, args.as_mut())
|
self.call_fn_dynamic_raw(scope, lib.as_ref(), name, &mut this_ptr, args.as_mut())
|
||||||
@ -1645,7 +1646,7 @@ impl Engine {
|
|||||||
name: &str,
|
name: &str,
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> FuncReturn<Dynamic> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let fn_def = lib
|
let fn_def = lib
|
||||||
.get_script_fn(name, args.len(), true)
|
.get_script_fn(name, args.len(), true)
|
||||||
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
.ok_or_else(|| EvalAltResult::ErrorFunctionNotFound(name.into(), Position::none()))?;
|
||||||
|
140
src/engine.rs
140
src/engine.rs
@ -1,12 +1,12 @@
|
|||||||
//! Main module defining the script evaluation `Engine`.
|
//! Main module defining the script evaluation `Engine`.
|
||||||
|
|
||||||
use crate::any::{map_std_type_name, Dynamic, Union};
|
use crate::any::{map_std_type_name, Dynamic, Union, Variant};
|
||||||
use crate::fn_call::run_builtin_op_assignment;
|
use crate::fn_call::run_builtin_op_assignment;
|
||||||
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{Expr, ReturnType, Stmt, INT};
|
use crate::parser::{Expr, ReturnType, Stmt};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -14,8 +14,8 @@ use crate::syntax::CustomSyntax;
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_fn_hash, StaticVec};
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
use crate::any::Variant;
|
use crate::parser::INT;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::ModuleResolver;
|
use crate::module::ModuleResolver;
|
||||||
@ -80,6 +80,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 12;
|
|||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub const MAX_EXPR_DEPTH: usize = 32;
|
pub const MAX_EXPR_DEPTH: usize = 32;
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
|
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 16;
|
||||||
|
|
||||||
@ -90,6 +91,7 @@ pub const MAX_CALL_STACK_DEPTH: usize = 128;
|
|||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
pub const MAX_EXPR_DEPTH: usize = 128;
|
pub const MAX_EXPR_DEPTH: usize = 128;
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(debug_assertions))]
|
#[cfg(not(debug_assertions))]
|
||||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
||||||
|
|
||||||
@ -144,6 +146,7 @@ impl IndexChainValue {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if not `IndexChainValue::Value`.
|
/// Panics if not `IndexChainValue::Value`.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn as_value(self) -> Dynamic {
|
pub fn as_value(self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
|
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
|
||||||
@ -155,6 +158,7 @@ impl IndexChainValue {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if not `IndexChainValue::FnCallArgs`.
|
/// Panics if not `IndexChainValue::FnCallArgs`.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
||||||
match self {
|
match self {
|
||||||
Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"),
|
Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"),
|
||||||
@ -178,7 +182,6 @@ impl From<Dynamic> for IndexChainValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A type that encapsulates a mutation target for an expression with side effects.
|
/// A type that encapsulates a mutation target for an expression with side effects.
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Target<'a> {
|
pub enum Target<'a> {
|
||||||
/// The target is a mutable reference to a `Dynamic` value somewhere.
|
/// The target is a mutable reference to a `Dynamic` value somewhere.
|
||||||
@ -196,7 +199,6 @@ pub enum Target<'a> {
|
|||||||
StringChar(&'a mut Dynamic, usize, Dynamic),
|
StringChar(&'a mut Dynamic, usize, Dynamic),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
impl<'a> Target<'a> {
|
impl<'a> Target<'a> {
|
||||||
/// Is the `Target` a reference pointing to other data?
|
/// Is the `Target` a reference pointing to other data?
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
@ -306,6 +308,7 @@ impl<'a> Target<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Update the value of the `Target`.
|
/// Update the value of the `Target`.
|
||||||
|
#[cfg(any(not(feature = "no_object"), not(feature = "no_index")))]
|
||||||
pub fn set_value(
|
pub fn set_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
new_val: (Dynamic, Position),
|
new_val: (Dynamic, Position),
|
||||||
@ -348,7 +351,6 @@ impl<'a> Target<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: &'a mut Dynamic) -> Self {
|
fn from(value: &'a mut Dynamic) -> Self {
|
||||||
@ -364,7 +366,6 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
|
||||||
impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(value: T) -> Self {
|
fn from(value: T) -> Self {
|
||||||
@ -414,35 +415,44 @@ pub struct Limits {
|
|||||||
///
|
///
|
||||||
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||||
pub max_call_stack_depth: usize,
|
pub max_call_stack_depth: usize,
|
||||||
/// Maximum depth of statements/expressions at global level.
|
/// Maximum depth of statements/expressions at global level (0 = unlimited).
|
||||||
pub max_expr_depth: usize,
|
pub max_expr_depth: usize,
|
||||||
/// Maximum depth of statements/expressions in functions.
|
/// Maximum depth of statements/expressions in functions (0 = unlimited).
|
||||||
|
/// Not available under `no_function`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub max_function_expr_depth: usize,
|
pub max_function_expr_depth: usize,
|
||||||
/// Maximum number of operations allowed to run.
|
/// Maximum number of operations allowed to run (0 = unlimited).
|
||||||
pub max_operations: u64,
|
pub max_operations: u64,
|
||||||
/// Maximum number of modules allowed to load.
|
/// Maximum number of modules allowed to load.
|
||||||
|
/// Not available under `no_module`.
|
||||||
|
#[cfg(not(feature = "no_modules"))]
|
||||||
pub max_modules: usize,
|
pub max_modules: usize,
|
||||||
/// Maximum length of a string.
|
/// Maximum length of a string (0 = unlimited).
|
||||||
pub max_string_size: usize,
|
pub max_string_size: usize,
|
||||||
/// Maximum length of an array.
|
/// Maximum length of an array (0 = unlimited).
|
||||||
|
/// Not available under `no_index`.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub max_array_size: usize,
|
pub max_array_size: usize,
|
||||||
/// Maximum number of properties in a map.
|
/// Maximum number of properties in a map (0 = unlimited).
|
||||||
|
/// Not available under `no_object`.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub max_map_size: usize,
|
pub max_map_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Context of a script evaluation process.
|
/// Context of a script evaluation process.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EvalContext<'e, 'a, 's, 'm, 't, 'd: 't> {
|
pub struct EvalContext<'e, 'a, 's, 'm, 't, 'd: 't> {
|
||||||
pub(crate) engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
pub(crate) mods: &'a mut Imports,
|
pub(crate) mods: &'a mut Imports,
|
||||||
pub(crate) state: &'s mut State,
|
pub(crate) state: &'s mut State,
|
||||||
pub(crate) lib: &'m Module,
|
lib: &'m Module,
|
||||||
pub(crate) this_ptr: &'t mut Option<&'d mut Dynamic>,
|
pub(crate) this_ptr: &'t mut Option<&'d mut Dynamic>,
|
||||||
pub(crate) level: usize,
|
level: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> {
|
impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> {
|
||||||
/// The current `Engine`.
|
/// The current `Engine`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn engine(&self) -> &'e Engine {
|
pub fn engine(&self) -> &'e Engine {
|
||||||
self.engine
|
self.engine
|
||||||
}
|
}
|
||||||
@ -450,14 +460,17 @@ impl<'e, 'a, 's, 'm, 't, 'd> EvalContext<'e, 'a, 's, 'm, 't, 'd> {
|
|||||||
/// Available under the `internals` feature only.
|
/// Available under the `internals` feature only.
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(not(feature = "no_modules"))]
|
#[cfg(not(feature = "no_modules"))]
|
||||||
|
#[inline(always)]
|
||||||
pub fn imports(&self) -> &'a Imports {
|
pub fn imports(&self) -> &'a Imports {
|
||||||
self.mods
|
self.mods
|
||||||
}
|
}
|
||||||
/// The global namespace containing definition of all script-defined functions.
|
/// The global namespace containing definition of all script-defined functions.
|
||||||
|
#[inline(always)]
|
||||||
pub fn namespace(&self) -> &'m Module {
|
pub fn namespace(&self) -> &'m Module {
|
||||||
self.lib
|
self.lib
|
||||||
}
|
}
|
||||||
/// The current nesting level of function calls.
|
/// The current nesting level of function calls.
|
||||||
|
#[inline(always)]
|
||||||
pub fn call_level(&self) -> usize {
|
pub fn call_level(&self) -> usize {
|
||||||
self.level
|
self.level
|
||||||
}
|
}
|
||||||
@ -516,7 +529,7 @@ pub struct Engine {
|
|||||||
|
|
||||||
/// Max limits.
|
/// Max limits.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
pub(crate) limits: Limits,
|
pub(crate) limits_set: Limits,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Engine {
|
impl fmt::Debug for Engine {
|
||||||
@ -662,14 +675,18 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
limits: Limits {
|
limits_set: Limits {
|
||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_operations: 0,
|
max_operations: 0,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
max_modules: usize::MAX,
|
max_modules: usize::MAX,
|
||||||
max_string_size: 0,
|
max_string_size: 0,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
max_array_size: 0,
|
max_array_size: 0,
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
max_map_size: 0,
|
max_map_size: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -710,14 +727,18 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
limits: Limits {
|
limits_set: Limits {
|
||||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||||
max_expr_depth: MAX_EXPR_DEPTH,
|
max_expr_depth: MAX_EXPR_DEPTH,
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||||
max_operations: 0,
|
max_operations: 0,
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
max_modules: usize::MAX,
|
max_modules: usize::MAX,
|
||||||
max_string_size: 0,
|
max_string_size: 0,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
max_array_size: 0,
|
max_array_size: 0,
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
max_map_size: 0,
|
max_map_size: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -1285,7 +1306,7 @@ impl Engine {
|
|||||||
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
||||||
self.inc_operations(state)?;
|
self.inc_operations(state)?;
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
let is_ref = target.is_ref();
|
let is_ref = target.is_ref();
|
||||||
|
|
||||||
let val = target.as_mut();
|
let val = target.as_mut();
|
||||||
@ -1542,7 +1563,7 @@ impl Engine {
|
|||||||
if func.is_plugin_fn() {
|
if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn().call(args)?;
|
func.get_plugin_fn().call(args)?;
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()(self, lib, args)?;
|
func.get_native_fn()((self, lib).into(), args)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Built-in op-assignment function
|
// Built-in op-assignment function
|
||||||
@ -1954,7 +1975,7 @@ impl Engine {
|
|||||||
|
|
||||||
// Guard against too many modules
|
// Guard against too many modules
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if state.modules >= self.limits.max_modules {
|
if state.modules >= self.max_modules() {
|
||||||
return EvalAltResult::ErrorTooManyModules(*_pos).into();
|
return EvalAltResult::ErrorTooManyModules(*_pos).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2042,8 +2063,19 @@ impl Engine {
|
|||||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
// If no data size limits, just return
|
// If no data size limits, just return
|
||||||
if self.limits.max_string_size + self.limits.max_array_size + self.limits.max_map_size == 0
|
let mut total = 0;
|
||||||
|
|
||||||
|
total += self.max_string_size();
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
|
total += self.max_array_size();
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
{
|
||||||
|
total += self.max_map_size();
|
||||||
|
}
|
||||||
|
|
||||||
|
if total == 0 {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2103,46 +2135,52 @@ impl Engine {
|
|||||||
// Simply return all errors
|
// Simply return all errors
|
||||||
Err(_) => return result,
|
Err(_) => return result,
|
||||||
// String with limit
|
// String with limit
|
||||||
Ok(Dynamic(Union::Str(_))) if self.limits.max_string_size > 0 => (),
|
Ok(Dynamic(Union::Str(_))) if self.max_string_size() > 0 => (),
|
||||||
// Array with limit
|
// Array with limit
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Ok(Dynamic(Union::Array(_))) if self.limits.max_array_size > 0 => (),
|
Ok(Dynamic(Union::Array(_))) if self.max_array_size() > 0 => (),
|
||||||
// Map with limit
|
// Map with limit
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Ok(Dynamic(Union::Map(_))) if self.limits.max_map_size > 0 => (),
|
Ok(Dynamic(Union::Map(_))) if self.max_map_size() > 0 => (),
|
||||||
// Everything else is simply returned
|
// Everything else is simply returned
|
||||||
Ok(_) => return result,
|
Ok(_) => return result,
|
||||||
};
|
};
|
||||||
|
|
||||||
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
let (_arr, _map, s) = calc_size(result.as_ref().unwrap());
|
||||||
|
|
||||||
if s > self.limits.max_string_size {
|
if s > self.max_string_size() {
|
||||||
EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
self.limits.max_string_size,
|
self.max_string_size(),
|
||||||
s,
|
s,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)
|
)
|
||||||
.into()
|
.into();
|
||||||
} else if arr > self.limits.max_array_size {
|
|
||||||
EvalAltResult::ErrorDataTooLarge(
|
|
||||||
"Size of array".to_string(),
|
|
||||||
self.limits.max_array_size,
|
|
||||||
arr,
|
|
||||||
Position::none(),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
} else if map > self.limits.max_map_size {
|
|
||||||
EvalAltResult::ErrorDataTooLarge(
|
|
||||||
"Number of properties in object map".to_string(),
|
|
||||||
self.limits.max_map_size,
|
|
||||||
map,
|
|
||||||
Position::none(),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
if _arr > self.max_array_size() {
|
||||||
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
|
"Size of array".to_string(),
|
||||||
|
self.max_array_size(),
|
||||||
|
_arr,
|
||||||
|
Position::none(),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
if _map > self.max_map_size() {
|
||||||
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
|
"Number of properties in object map".to_string(),
|
||||||
|
self.max_map_size(),
|
||||||
|
_map,
|
||||||
|
Position::none(),
|
||||||
|
)
|
||||||
|
.into();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the number of operations stay within limit.
|
/// Check if the number of operations stay within limit.
|
||||||
@ -2152,7 +2190,7 @@ impl Engine {
|
|||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
// Guard against too many operations
|
// Guard against too many operations
|
||||||
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
|
if self.max_operations() > 0 && state.operations > self.max_operations() {
|
||||||
return EvalAltResult::ErrorTooManyOperations(Position::none()).into();
|
return EvalAltResult::ErrorTooManyOperations(Position::none()).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,7 +208,7 @@ impl Engine {
|
|||||||
let result = if func.is_plugin_fn() {
|
let result = if func.is_plugin_fn() {
|
||||||
func.get_plugin_fn().call(args)
|
func.get_plugin_fn().call(args)
|
||||||
} else {
|
} else {
|
||||||
func.get_native_fn()(self, lib, args)
|
func.get_native_fn()((self, lib).into(), args)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
@ -356,7 +356,7 @@ impl Engine {
|
|||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if level > self.limits.max_call_stack_depth {
|
if level > self.max_call_levels() {
|
||||||
return Err(Box::new(
|
return Err(Box::new(
|
||||||
EvalAltResult::ErrorStackOverflow(Position::none()),
|
EvalAltResult::ErrorStackOverflow(Position::none()),
|
||||||
));
|
));
|
||||||
@ -648,7 +648,7 @@ impl Engine {
|
|||||||
// Check for stack overflow
|
// Check for stack overflow
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _level > self.limits.max_call_stack_depth {
|
if _level > self.max_call_levels() {
|
||||||
return Err(Box::new(
|
return Err(Box::new(
|
||||||
EvalAltResult::ErrorStackOverflow(Position::none()),
|
EvalAltResult::ErrorStackOverflow(Position::none()),
|
||||||
));
|
));
|
||||||
@ -1196,7 +1196,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
f.get_native_fn()(self, lib, args.as_mut())
|
f.get_native_fn()((self, lib).into(), args.as_mut())
|
||||||
}
|
}
|
||||||
Some(_) => unreachable!(),
|
Some(_) => unreachable!(),
|
||||||
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
None if def_val.is_some() => Ok(def_val.unwrap().into()),
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
//! Module defining interfaces to native-Rust functions.
|
//! Module defining interfaces to native-Rust functions.
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::engine::{Engine, EvalContext};
|
use crate::engine::{Engine, EvalContext, FN_ANONYMOUS};
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{FnAccess, ScriptFnDef};
|
use crate::parser::{FnAccess, ScriptFnDef};
|
||||||
use crate::plugin::PluginFunction;
|
use crate::plugin::PluginFunction;
|
||||||
@ -46,6 +46,35 @@ pub type Locked<T> = RefCell<T>;
|
|||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type Locked<T> = RwLock<T>;
|
pub type Locked<T> = RwLock<T>;
|
||||||
|
|
||||||
|
/// Context of a script evaluation process.
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct NativeCallContext<'e, 'm> {
|
||||||
|
engine: &'e Engine,
|
||||||
|
lib: &'m Module,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'e, 'm> From<(&'e Engine, &'m Module)> for NativeCallContext<'e, 'm> {
|
||||||
|
fn from(value: (&'e Engine, &'m Module)) -> Self {
|
||||||
|
Self {
|
||||||
|
engine: value.0,
|
||||||
|
lib: value.1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'e, 'm> NativeCallContext<'e, 'm> {
|
||||||
|
/// The current `Engine`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn engine(&self) -> &'e Engine {
|
||||||
|
self.engine
|
||||||
|
}
|
||||||
|
/// The global namespace containing definition of all script-defined functions.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn namespace(&self) -> &'m Module {
|
||||||
|
self.lib
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume a `Shared` resource and return a mutable reference to the wrapped value.
|
/// Consume a `Shared` resource and return a mutable reference to the wrapped value.
|
||||||
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
|
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
|
||||||
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
|
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
|
||||||
@ -108,6 +137,11 @@ impl FnPtr {
|
|||||||
pub fn curry(&self) -> &[Dynamic] {
|
pub fn curry(&self) -> &[Dynamic] {
|
||||||
self.1.as_ref()
|
self.1.as_ref()
|
||||||
}
|
}
|
||||||
|
/// Does this function pointer refer to an anonymous function?
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn is_anonymous(&self) -> bool {
|
||||||
|
self.0.starts_with(FN_ANONYMOUS)
|
||||||
|
}
|
||||||
|
|
||||||
/// Call the function pointer with curried arguments (if any).
|
/// Call the function pointer with curried arguments (if any).
|
||||||
///
|
///
|
||||||
@ -121,8 +155,7 @@ impl FnPtr {
|
|||||||
/// clone them _before_ calling this function.
|
/// clone them _before_ calling this function.
|
||||||
pub fn call_dynamic(
|
pub fn call_dynamic(
|
||||||
&self,
|
&self,
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: impl AsRef<Module>,
|
|
||||||
this_ptr: Option<&mut Dynamic>,
|
this_ptr: Option<&mut Dynamic>,
|
||||||
mut arg_values: impl AsMut<[Dynamic]>,
|
mut arg_values: impl AsMut<[Dynamic]>,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
@ -144,10 +177,11 @@ impl FnPtr {
|
|||||||
args.insert(0, obj);
|
args.insert(0, obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine
|
context
|
||||||
|
.engine()
|
||||||
.exec_fn_call(
|
.exec_fn_call(
|
||||||
&mut Default::default(),
|
&mut Default::default(),
|
||||||
lib.as_ref(),
|
context.namespace(),
|
||||||
fn_name,
|
fn_name,
|
||||||
hash_script,
|
hash_script,
|
||||||
args.as_mut(),
|
args.as_mut(),
|
||||||
@ -204,11 +238,11 @@ impl TryFrom<&str> for FnPtr {
|
|||||||
|
|
||||||
/// A general function trail object.
|
/// A general function trail object.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type FnAny = dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
|
pub type FnAny = dyn Fn(NativeCallContext, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>>;
|
||||||
/// A general function trail object.
|
/// A general function trail object.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type FnAny =
|
pub type FnAny =
|
||||||
dyn Fn(&Engine, &Module, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
|
dyn Fn(NativeCallContext, &mut FnCallArgs) -> Result<Dynamic, Box<EvalAltResult>> + Send + Sync;
|
||||||
|
|
||||||
/// A standard function that gets an iterator from a type.
|
/// A standard function that gets an iterator from a type.
|
||||||
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
pub type IteratorFn = fn(Dynamic) -> Box<dyn Iterator<Item = Dynamic>>;
|
||||||
|
@ -4,8 +4,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, DynamicWriteLock, Variant};
|
use crate::any::{Dynamic, DynamicWriteLock, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, SendSync};
|
use crate::fn_native::{CallableFunction, FnAny, FnCallArgs, NativeCallContext, SendSync};
|
||||||
use crate::module::Module;
|
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::FnAccess;
|
||||||
use crate::r#unsafe::unsafe_cast_box;
|
use crate::r#unsafe::unsafe_cast_box;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -127,7 +126,7 @@ macro_rules! make_func {
|
|||||||
// ^ dereferencing function
|
// ^ dereferencing function
|
||||||
// ^ argument reference expression(like A, *B, &mut C etc)
|
// ^ argument reference expression(like A, *B, &mut C etc)
|
||||||
|
|
||||||
Box::new(move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
Box::new(move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
// The arguments are assumed to be of the correct number and types!
|
// The arguments are assumed to be of the correct number and types!
|
||||||
|
|
||||||
let mut _drain = args.iter_mut();
|
let mut _drain = args.iter_mut();
|
||||||
|
@ -85,7 +85,7 @@ mod utils;
|
|||||||
pub use any::Dynamic;
|
pub use any::Dynamic;
|
||||||
pub use engine::{Engine, EvalContext};
|
pub use engine::{Engine, EvalContext};
|
||||||
pub use error::{ParseError, ParseErrorType};
|
pub use error::{ParseError, ParseErrorType};
|
||||||
pub use fn_native::FnPtr;
|
pub use fn_native::{FnPtr, NativeCallContext};
|
||||||
pub use fn_register::{RegisterFn, RegisterResultFn};
|
pub use fn_register::{RegisterFn, RegisterResultFn};
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use parser::{ImmutableString, AST, INT};
|
pub use parser::{ImmutableString, AST, INT};
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::Engine;
|
use crate::engine::Engine;
|
||||||
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, SendSync};
|
use crate::fn_native::{CallableFunction, FnCallArgs, IteratorFn, NativeCallContext, SendSync};
|
||||||
use crate::fn_register::by_value as cast_arg;
|
use crate::fn_register::by_value as cast_arg;
|
||||||
use crate::parser::FnAccess;
|
use crate::parser::FnAccess;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -24,7 +24,11 @@ use crate::{
|
|||||||
use crate::engine::{Array, FN_IDX_GET, FN_IDX_SET};
|
use crate::engine::{Array, FN_IDX_GET, FN_IDX_SET};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::{make_getter, make_setter, Map};
|
use crate::engine::{make_getter, make_setter};
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
use crate::engine::Map;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
@ -38,9 +42,6 @@ use crate::stdlib::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Return type of module-level Rust function.
|
|
||||||
pub type FuncReturn<T> = Result<T, Box<EvalAltResult>>;
|
|
||||||
|
|
||||||
pub type FuncInfo = (
|
pub type FuncInfo = (
|
||||||
String,
|
String,
|
||||||
FnAccess,
|
FnAccess,
|
||||||
@ -536,10 +537,12 @@ impl Module {
|
|||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
arg_types: &[TypeId],
|
arg_types: &[TypeId],
|
||||||
func: impl Fn(&Engine, &Module, &mut [&mut Dynamic]) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(NativeCallContext, &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>>
|
||||||
|
+ SendSync
|
||||||
|
+ 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |engine: &Engine, lib: &Module, args: &mut FnCallArgs| {
|
let f = move |context: NativeCallContext, args: &mut [&mut Dynamic]| {
|
||||||
func(engine, lib, args).map(Dynamic::from)
|
func(context, args).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
name,
|
name,
|
||||||
@ -566,9 +569,9 @@ impl Module {
|
|||||||
pub fn set_fn_0<T: Variant + Clone>(
|
pub fn set_fn_0<T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn() -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn() -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, _: &mut FnCallArgs| func().map(Dynamic::from);
|
let f = move |_: NativeCallContext, _: &mut FnCallArgs| func().map(Dynamic::from);
|
||||||
let arg_types = [];
|
let arg_types = [];
|
||||||
self.set_fn(
|
self.set_fn(
|
||||||
name,
|
name,
|
||||||
@ -595,9 +598,9 @@ impl Module {
|
|||||||
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_1<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
|
func(cast_arg::<A>(&mut args[0])).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>()];
|
let arg_types = [TypeId::of::<A>()];
|
||||||
@ -626,9 +629,9 @@ impl Module {
|
|||||||
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_1_mut<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
|
func(&mut args[0].write_lock::<A>().unwrap()).map(Dynamic::from)
|
||||||
};
|
};
|
||||||
let arg_types = [TypeId::of::<A>()];
|
let arg_types = [TypeId::of::<A>()];
|
||||||
@ -658,7 +661,7 @@ impl Module {
|
|||||||
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
pub fn set_getter_fn<A: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.set_fn_1_mut(make_getter(&name.into()), func)
|
self.set_fn_1_mut(make_getter(&name.into()), func)
|
||||||
}
|
}
|
||||||
@ -682,9 +685,9 @@ impl Module {
|
|||||||
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_2<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
|
|
||||||
@ -719,9 +722,9 @@ impl Module {
|
|||||||
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_fn_2_mut<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
|
|
||||||
@ -758,7 +761,7 @@ impl Module {
|
|||||||
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
|
pub fn set_setter_fn<A: Variant + Clone, B: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A, B) -> FuncReturn<()> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
self.set_fn_2_mut(make_setter(&name.into()), func)
|
self.set_fn_2_mut(make_setter(&name.into()), func)
|
||||||
}
|
}
|
||||||
@ -788,7 +791,7 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||||
panic!("Cannot register indexer for arrays.");
|
panic!("Cannot register indexer for arrays.");
|
||||||
@ -831,9 +834,9 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B, C) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let c = cast_arg::<C>(&mut args[2]);
|
let c = cast_arg::<C>(&mut args[2]);
|
||||||
@ -874,9 +877,9 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A, B, C) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[2]);
|
let b = cast_arg::<B>(&mut args[2]);
|
||||||
let c = cast_arg::<C>(&mut args[3]);
|
let c = cast_arg::<C>(&mut args[3]);
|
||||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
@ -918,7 +921,7 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
pub fn set_indexer_set_fn<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
func: impl Fn(&mut A, B, C) -> FuncReturn<()> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||||
panic!("Cannot register indexer for arrays.");
|
panic!("Cannot register indexer for arrays.");
|
||||||
@ -934,7 +937,7 @@ impl Module {
|
|||||||
panic!("Cannot register indexer for strings.");
|
panic!("Cannot register indexer for strings.");
|
||||||
}
|
}
|
||||||
|
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let c = cast_arg::<C>(&mut args[2]);
|
let c = cast_arg::<C>(&mut args[2]);
|
||||||
let a = &mut args[0].write_lock::<A>().unwrap();
|
let a = &mut args[0].write_lock::<A>().unwrap();
|
||||||
@ -982,8 +985,8 @@ impl Module {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
pub fn set_indexer_get_set_fn<A: Variant + Clone, B: Variant + Clone, T: Variant + Clone>(
|
||||||
&mut self,
|
&mut self,
|
||||||
getter: impl Fn(&mut A, B) -> FuncReturn<T> + SendSync + 'static,
|
getter: impl Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
setter: impl Fn(&mut A, B, T) -> FuncReturn<()> + SendSync + 'static,
|
setter: impl Fn(&mut A, B, T) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> (u64, u64) {
|
) -> (u64, u64) {
|
||||||
(
|
(
|
||||||
self.set_indexer_get_fn(getter),
|
self.set_indexer_get_fn(getter),
|
||||||
@ -1016,9 +1019,9 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let a = cast_arg::<A>(&mut args[0]);
|
let a = cast_arg::<A>(&mut args[0]);
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let c = cast_arg::<C>(&mut args[2]);
|
let c = cast_arg::<C>(&mut args[2]);
|
||||||
@ -1066,9 +1069,9 @@ impl Module {
|
|||||||
>(
|
>(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: impl Into<String>,
|
name: impl Into<String>,
|
||||||
func: impl Fn(&mut A, B, C, D) -> FuncReturn<T> + SendSync + 'static,
|
func: impl Fn(&mut A, B, C, D) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||||
) -> u64 {
|
) -> u64 {
|
||||||
let f = move |_: &Engine, _: &Module, args: &mut FnCallArgs| {
|
let f = move |_: NativeCallContext, args: &mut FnCallArgs| {
|
||||||
let b = cast_arg::<B>(&mut args[1]);
|
let b = cast_arg::<B>(&mut args[1]);
|
||||||
let c = cast_arg::<C>(&mut args[2]);
|
let c = cast_arg::<C>(&mut args[2]);
|
||||||
let d = cast_arg::<D>(&mut args[3]);
|
let d = cast_arg::<D>(&mut args[3]);
|
||||||
@ -1340,7 +1343,11 @@ impl Module {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub fn eval_ast_as_new(mut scope: Scope, ast: &AST, engine: &Engine) -> FuncReturn<Self> {
|
pub fn eval_ast_as_new(
|
||||||
|
mut scope: Scope,
|
||||||
|
ast: &AST,
|
||||||
|
engine: &Engine,
|
||||||
|
) -> Result<Self, Box<EvalAltResult>> {
|
||||||
let mut mods = Imports::new();
|
let mut mods = Imports::new();
|
||||||
|
|
||||||
// Run the script
|
// Run the script
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::{Array, Engine};
|
use crate::engine::Array;
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::{FnPtr, NativeCallContext};
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
@ -239,21 +239,20 @@ mod array_functions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn pad<T: Variant + Clone>(
|
fn pad<T: Variant + Clone>(
|
||||||
_engine: &Engine,
|
_context: NativeCallContext,
|
||||||
_: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<(), Box<EvalAltResult>> {
|
) -> Result<(), Box<EvalAltResult>> {
|
||||||
let len = *args[1].read_lock::<INT>().unwrap();
|
let len = *args[1].read_lock::<INT>().unwrap();
|
||||||
|
|
||||||
// Check if array will be over max size limit
|
// Check if array will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _engine.limits.max_array_size > 0
|
if _context.engine().max_array_size() > 0
|
||||||
&& len > 0
|
&& len > 0
|
||||||
&& (len as usize) > _engine.limits.max_array_size
|
&& (len as usize) > _context.engine().max_array_size()
|
||||||
{
|
{
|
||||||
return EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Size of array".to_string(),
|
"Size of array".to_string(),
|
||||||
_engine.limits.max_array_size,
|
_context.engine().max_array_size(),
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)
|
)
|
||||||
@ -271,11 +270,7 @@ fn pad<T: Variant + Clone>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map(
|
fn map(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<Array, Box<EvalAltResult>> {
|
||||||
engine: &Engine,
|
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
|
||||||
) -> Result<Array, Box<EvalAltResult>> {
|
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
let mapper = args[1].read_lock::<FnPtr>().unwrap();
|
let mapper = args[1].read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
@ -284,10 +279,10 @@ fn map(
|
|||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
array.push(
|
array.push(
|
||||||
mapper
|
mapper
|
||||||
.call_dynamic(engine, lib, None, [item.clone()])
|
.call_dynamic(context, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
mapper.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
|
mapper.call_dynamic(context, None, [item.clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -305,8 +300,7 @@ fn map(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn filter(
|
fn filter(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Array, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
@ -316,10 +310,10 @@ fn filter(
|
|||||||
|
|
||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
if filter
|
if filter
|
||||||
.call_dynamic(engine, lib, None, [item.clone()])
|
.call_dynamic(context, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
|
filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -340,20 +334,16 @@ fn filter(
|
|||||||
Ok(array)
|
Ok(array)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn some(
|
fn some(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
|
||||||
engine: &Engine,
|
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
if filter
|
if filter
|
||||||
.call_dynamic(engine, lib, None, [item.clone()])
|
.call_dynamic(context, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
|
filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -374,20 +364,16 @@ fn some(
|
|||||||
Ok(false.into())
|
Ok(false.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn all(
|
fn all(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<bool, Box<EvalAltResult>> {
|
||||||
engine: &Engine,
|
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
|
||||||
) -> Result<bool, Box<EvalAltResult>> {
|
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
let filter = args[1].read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
if !filter
|
if !filter
|
||||||
.call_dynamic(engine, lib, None, [item.clone()])
|
.call_dynamic(context, None, [item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
filter.call_dynamic(engine, lib, None, [item.clone(), (i as INT).into()])
|
filter.call_dynamic(context, None, [item.clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -409,8 +395,7 @@ fn all(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reduce(
|
fn reduce(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
@ -420,14 +405,11 @@ fn reduce(
|
|||||||
|
|
||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
result = reducer
|
result = reducer
|
||||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
engine,
|
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||||
lib,
|
}
|
||||||
None,
|
|
||||||
[result, item.clone(), (i as INT).into()],
|
|
||||||
),
|
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -443,15 +425,14 @@ fn reduce(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_with_initial(
|
fn reduce_with_initial(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
let reducer = args[1].read_lock::<FnPtr>().unwrap();
|
let reducer = args[1].read_lock::<FnPtr>().unwrap();
|
||||||
let initial = args[2].read_lock::<FnPtr>().unwrap();
|
let initial = args[2].read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
let mut result = initial.call_dynamic(engine, lib, None, []).map_err(|err| {
|
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||||
"reduce".to_string(),
|
"reduce".to_string(),
|
||||||
err,
|
err,
|
||||||
@ -461,14 +442,11 @@ fn reduce_with_initial(
|
|||||||
|
|
||||||
for (i, item) in list.iter().enumerate() {
|
for (i, item) in list.iter().enumerate() {
|
||||||
result = reducer
|
result = reducer
|
||||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
engine,
|
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||||
lib,
|
}
|
||||||
None,
|
|
||||||
[result, item.clone(), (i as INT).into()],
|
|
||||||
),
|
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -484,8 +462,7 @@ fn reduce_with_initial(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_rev(
|
fn reduce_rev(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
@ -495,14 +472,11 @@ fn reduce_rev(
|
|||||||
|
|
||||||
for (i, item) in list.iter().enumerate().rev() {
|
for (i, item) in list.iter().enumerate().rev() {
|
||||||
result = reducer
|
result = reducer
|
||||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
engine,
|
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||||
lib,
|
}
|
||||||
None,
|
|
||||||
[result, item.clone(), (i as INT).into()],
|
|
||||||
),
|
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -518,15 +492,14 @@ fn reduce_rev(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn reduce_rev_with_initial(
|
fn reduce_rev_with_initial(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let list = args[0].read_lock::<Array>().unwrap();
|
let list = args[0].read_lock::<Array>().unwrap();
|
||||||
let reducer = args[1].read_lock::<FnPtr>().unwrap();
|
let reducer = args[1].read_lock::<FnPtr>().unwrap();
|
||||||
let initial = args[2].read_lock::<FnPtr>().unwrap();
|
let initial = args[2].read_lock::<FnPtr>().unwrap();
|
||||||
|
|
||||||
let mut result = initial.call_dynamic(engine, lib, None, []).map_err(|err| {
|
let mut result = initial.call_dynamic(context, None, []).map_err(|err| {
|
||||||
Box::new(EvalAltResult::ErrorInFunctionCall(
|
Box::new(EvalAltResult::ErrorInFunctionCall(
|
||||||
"reduce".to_string(),
|
"reduce".to_string(),
|
||||||
err,
|
err,
|
||||||
@ -536,14 +509,11 @@ fn reduce_rev_with_initial(
|
|||||||
|
|
||||||
for (i, item) in list.iter().enumerate().rev() {
|
for (i, item) in list.iter().enumerate().rev() {
|
||||||
result = reducer
|
result = reducer
|
||||||
.call_dynamic(engine, lib, None, [result.clone(), item.clone()])
|
.call_dynamic(context, None, [result.clone(), item.clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => reducer.call_dynamic(
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
engine,
|
reducer.call_dynamic(context, None, [result, item.clone(), (i as INT).into()])
|
||||||
lib,
|
}
|
||||||
None,
|
|
||||||
[result, item.clone(), (i as INT).into()],
|
|
||||||
),
|
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
.map_err(|err| {
|
.map_err(|err| {
|
||||||
@ -559,8 +529,7 @@ fn reduce_rev_with_initial(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sort(
|
fn sort(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let comparer = args[1].read_lock::<FnPtr>().unwrap().clone();
|
let comparer = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||||
@ -568,7 +537,7 @@ fn sort(
|
|||||||
|
|
||||||
list.sort_by(|x, y| {
|
list.sort_by(|x, y| {
|
||||||
comparer
|
comparer
|
||||||
.call_dynamic(engine, lib, None, [x.clone(), y.clone()])
|
.call_dynamic(context, None, [x.clone(), y.clone()])
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|v| v.as_int().ok())
|
.and_then(|v| v.as_int().ok())
|
||||||
.map(|v| {
|
.map(|v| {
|
||||||
@ -598,8 +567,7 @@ fn sort(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn drain(
|
fn drain(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Array, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||||
@ -613,10 +581,10 @@ fn drain(
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
if filter
|
if filter
|
||||||
.call_dynamic(engine, lib, None, [list[i].clone()])
|
.call_dynamic(context, None, [list[i].clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
filter.call_dynamic(engine, lib, None, [list[i].clone(), (i as INT).into()])
|
filter.call_dynamic(context, None, [list[i].clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
@ -638,8 +606,7 @@ fn drain(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn retain(
|
fn retain(
|
||||||
engine: &Engine,
|
context: NativeCallContext,
|
||||||
lib: &Module,
|
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut [&mut Dynamic],
|
||||||
) -> Result<Array, Box<EvalAltResult>> {
|
) -> Result<Array, Box<EvalAltResult>> {
|
||||||
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
let filter = args[1].read_lock::<FnPtr>().unwrap().clone();
|
||||||
@ -653,10 +620,10 @@ fn retain(
|
|||||||
i -= 1;
|
i -= 1;
|
||||||
|
|
||||||
if !filter
|
if !filter
|
||||||
.call_dynamic(engine, lib, None, [list[i].clone()])
|
.call_dynamic(context, None, [list[i].clone()])
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
EvalAltResult::ErrorFunctionNotFound(_, _) => {
|
||||||
filter.call_dynamic(engine, lib, None, [list[i].clone(), (i as INT).into()])
|
filter.call_dynamic(context, None, [list[i].clone(), (i as INT).into()])
|
||||||
}
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
|
@ -12,4 +12,8 @@ mod fn_ptr_functions {
|
|||||||
pub fn name(f: &mut FnPtr) -> ImmutableString {
|
pub fn name(f: &mut FnPtr) -> ImmutableString {
|
||||||
f.get_fn_name().clone()
|
f.get_fn_name().clone()
|
||||||
}
|
}
|
||||||
|
#[rhai_fn(name = "is_anonymous", get = "is_anonymous")]
|
||||||
|
pub fn is_anonymous(f: &mut FnPtr) -> bool {
|
||||||
|
f.is_anonymous()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
use crate::any::Variant;
|
use crate::any::Variant;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::module::FuncReturn;
|
|
||||||
use crate::parser::INT;
|
use crate::parser::INT;
|
||||||
|
use crate::result::EvalAltResult;
|
||||||
|
|
||||||
use crate::stdlib::ops::{Add, Range};
|
use crate::stdlib::ops::{Add, Range};
|
||||||
|
|
||||||
fn get_range<T: Variant + Clone>(from: T, to: T) -> FuncReturn<Range<T>> {
|
fn get_range<T: Variant + Clone>(from: T, to: T) -> Result<Range<T>, Box<EvalAltResult>> {
|
||||||
Ok(from..to)
|
Ok(from..to)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_step_range<T>(from: T, to: T, step: T) -> FuncReturn<StepRange<T>>
|
fn get_step_range<T>(from: T, to: T, step: T) -> Result<StepRange<T>, Box<EvalAltResult>>
|
||||||
where
|
where
|
||||||
for<'a> &'a T: Add<&'a T, Output = T>,
|
for<'a> &'a T: Add<&'a T, Output = T>,
|
||||||
T: Variant + Clone + PartialOrd,
|
T: Variant + Clone + PartialOrd,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::def_package;
|
use crate::def_package;
|
||||||
use crate::engine::Engine;
|
|
||||||
use crate::fn_native::FnPtr;
|
use crate::fn_native::FnPtr;
|
||||||
use crate::parser::{ImmutableString, INT};
|
use crate::parser::{ImmutableString, INT};
|
||||||
use crate::plugin::*;
|
use crate::plugin::*;
|
||||||
@ -62,15 +61,17 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
lib.set_raw_fn(
|
lib.set_raw_fn(
|
||||||
"pad",
|
"pad",
|
||||||
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|
&[TypeId::of::<ImmutableString>(), TypeId::of::<INT>(), TypeId::of::<char>()],
|
||||||
|_engine: &Engine, _: &Module, args: &mut [&mut Dynamic]| {
|
|_context, args| {
|
||||||
let len = *args[1].read_lock::<INT>().unwrap();
|
let len = *args[1].read_lock::<INT>().unwrap();
|
||||||
|
|
||||||
// Check if string will be over max size limit
|
// Check if string will be over max size limit
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _engine.limits.max_string_size > 0 && len > 0 && (len as usize) > _engine.limits.max_string_size {
|
if _context.engine().max_string_size() > 0 && len > 0
|
||||||
|
&& (len as usize) > _context.engine().max_string_size()
|
||||||
|
{
|
||||||
return EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
_engine.limits.max_string_size,
|
_context.engine().max_string_size(),
|
||||||
len as usize,
|
len as usize,
|
||||||
Position::none(),
|
Position::none(),
|
||||||
).into();
|
).into();
|
||||||
@ -90,10 +91,10 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if _engine.limits.max_string_size > 0 && s.len() > _engine.limits.max_string_size {
|
if _context.engine().max_string_size() > 0 && s.len() > _context.engine().max_string_size() {
|
||||||
return EvalAltResult::ErrorDataTooLarge(
|
return EvalAltResult::ErrorDataTooLarge(
|
||||||
"Length of string".to_string(),
|
"Length of string".to_string(),
|
||||||
_engine.limits.max_string_size,
|
_context.engine().max_string_size(),
|
||||||
s.len(),
|
s.len(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
).into();
|
).into();
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
//! Main module defining the lexer and parser.
|
//! Main module defining the lexer and parser.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
use crate::engine::{
|
use crate::engine::{Engine, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT};
|
||||||
Engine, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_THIS, MARKER_BLOCK, MARKER_EXPR, MARKER_IDENT,
|
|
||||||
};
|
|
||||||
use crate::error::{LexError, ParseError, ParseErrorType};
|
use crate::error::{LexError, ParseError, ParseErrorType};
|
||||||
use crate::fn_native::{FnPtr, Shared};
|
use crate::fn_native::{FnPtr, Shared};
|
||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
@ -18,7 +16,7 @@ use crate::{calc_fn_hash, StaticVec};
|
|||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::{make_getter, make_setter, Map};
|
use crate::engine::{make_getter, make_setter, Map, KEYWORD_EVAL, KEYWORD_FN_PTR};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
|
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
|
||||||
@ -603,13 +601,15 @@ struct ParseState<'e> {
|
|||||||
/// All consequent calls to `access_var` will not be affected
|
/// All consequent calls to `access_var` will not be affected
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: bool,
|
allow_capture: bool,
|
||||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// Encapsulates a local stack with imported module names.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Vec<String>,
|
modules: Vec<String>,
|
||||||
/// Maximum levels of expression nesting.
|
/// Maximum levels of expression nesting.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
/// Maximum levels of expression nesting in functions.
|
/// Maximum levels of expression nesting in functions.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth: usize,
|
max_function_expr_depth: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -619,19 +619,23 @@ impl<'e> ParseState<'e> {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
|
#[cfg(not(feature = "unchecked"))] max_expr_depth: usize,
|
||||||
#[cfg(not(feature = "unchecked"))] max_function_expr_depth: usize,
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
max_function_expr_depth: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth,
|
max_expr_depth,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
max_function_expr_depth,
|
max_function_expr_depth,
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: Default::default(),
|
externals: Default::default(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1696,11 +1700,10 @@ fn parse_array_literal(
|
|||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if state.engine.limits.max_array_size > 0 && arr.len() >= state.engine.limits.max_array_size
|
if state.engine.max_array_size() > 0 && arr.len() >= state.engine.max_array_size() {
|
||||||
{
|
|
||||||
return Err(PERR::LiteralTooLarge(
|
return Err(PERR::LiteralTooLarge(
|
||||||
"Size of array literal".to_string(),
|
"Size of array literal".to_string(),
|
||||||
state.engine.limits.max_array_size,
|
state.engine.max_array_size(),
|
||||||
)
|
)
|
||||||
.into_err(input.peek().unwrap().1));
|
.into_err(input.peek().unwrap().1));
|
||||||
}
|
}
|
||||||
@ -1804,10 +1807,10 @@ fn parse_map_literal(
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
if state.engine.limits.max_map_size > 0 && map.len() >= state.engine.limits.max_map_size {
|
if state.engine.max_map_size() > 0 && map.len() >= state.engine.max_map_size() {
|
||||||
return Err(PERR::LiteralTooLarge(
|
return Err(PERR::LiteralTooLarge(
|
||||||
"Number of properties in object map literal".to_string(),
|
"Number of properties in object map literal".to_string(),
|
||||||
state.engine.limits.max_map_size,
|
state.engine.max_map_size(),
|
||||||
)
|
)
|
||||||
.into_err(input.peek().unwrap().1));
|
.into_err(input.peek().unwrap().1));
|
||||||
}
|
}
|
||||||
@ -3599,9 +3602,10 @@ impl Engine {
|
|||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.limits.max_expr_depth,
|
self.max_expr_depth(),
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.limits.max_function_expr_depth,
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
self.max_function_expr_depth(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let settings = ParseSettings {
|
let settings = ParseSettings {
|
||||||
@ -3646,9 +3650,10 @@ impl Engine {
|
|||||||
let mut state = ParseState::new(
|
let mut state = ParseState::new(
|
||||||
self,
|
self,
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.limits.max_expr_depth,
|
self.max_expr_depth(),
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
self.limits.max_function_expr_depth,
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
self.max_function_expr_depth(),
|
||||||
);
|
);
|
||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
|
@ -53,7 +53,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
|
pub fn set_max_call_levels(&mut self, levels: usize) -> &mut Self {
|
||||||
self.limits.max_call_stack_depth = levels;
|
self.limits_set.max_call_stack_depth = levels;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,7 +61,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_call_levels(&self) -> usize {
|
pub fn max_call_levels(&self) -> usize {
|
||||||
self.limits.max_call_stack_depth
|
self.limits_set.max_call_stack_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of operations allowed for a script to run to avoid
|
/// Set the maximum number of operations allowed for a script to run to avoid
|
||||||
@ -69,7 +69,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
pub fn set_max_operations(&mut self, operations: u64) -> &mut Self {
|
||||||
self.limits.max_operations = if operations == u64::MAX {
|
self.limits_set.max_operations = if operations == u64::MAX {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
operations
|
operations
|
||||||
@ -81,14 +81,14 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_operations(&self) -> u64 {
|
pub fn max_operations(&self) -> u64 {
|
||||||
self.limits.max_operations
|
self.limits_set.max_operations
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum number of imported modules allowed for a script.
|
/// Set the maximum number of imported modules allowed for a script.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
|
pub fn set_max_modules(&mut self, modules: usize) -> &mut Self {
|
||||||
self.limits.max_modules = modules;
|
self.limits_set.max_modules = modules;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_modules(&self) -> usize {
|
pub fn max_modules(&self) -> usize {
|
||||||
self.limits.max_modules
|
self.limits_set.max_modules
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the depth limits for expressions (0 for unlimited).
|
/// Set the depth limits for expressions (0 for unlimited).
|
||||||
@ -105,18 +105,21 @@ impl Engine {
|
|||||||
pub fn set_max_expr_depths(
|
pub fn set_max_expr_depths(
|
||||||
&mut self,
|
&mut self,
|
||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
max_function_expr_depth: usize,
|
#[cfg(not(feature = "no_function"))] max_function_expr_depth: usize,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.limits.max_expr_depth = if max_expr_depth == usize::MAX {
|
self.limits_set.max_expr_depth = if max_expr_depth == usize::MAX {
|
||||||
0
|
0
|
||||||
} else {
|
} else {
|
||||||
max_expr_depth
|
max_expr_depth
|
||||||
};
|
};
|
||||||
self.limits.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
#[cfg(not(feature = "no_function"))]
|
||||||
0
|
{
|
||||||
} else {
|
self.limits_set.max_function_expr_depth = if max_function_expr_depth == usize::MAX {
|
||||||
max_function_expr_depth
|
0
|
||||||
};
|
} else {
|
||||||
|
max_function_expr_depth
|
||||||
|
};
|
||||||
|
}
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,21 +127,22 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_expr_depth(&self) -> usize {
|
pub fn max_expr_depth(&self) -> usize {
|
||||||
self.limits.max_expr_depth
|
self.limits_set.max_expr_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The depth limit for expressions in functions (0 for unlimited).
|
/// The depth limit for expressions in functions (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_function_expr_depth(&self) -> usize {
|
pub fn max_function_expr_depth(&self) -> usize {
|
||||||
self.limits.max_function_expr_depth
|
self.limits_set.max_function_expr_depth
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of strings (0 for unlimited).
|
/// Set the maximum length of strings (0 for unlimited).
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_string_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits_set.max_string_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -146,7 +150,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_string_size(&self) -> usize {
|
pub fn max_string_size(&self) -> usize {
|
||||||
self.limits.max_string_size
|
self.limits_set.max_string_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of arrays (0 for unlimited).
|
/// Set the maximum length of arrays (0 for unlimited).
|
||||||
@ -154,7 +158,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_array_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits_set.max_array_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +167,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_array_size(&self) -> usize {
|
pub fn max_array_size(&self) -> usize {
|
||||||
self.limits.max_array_size
|
self.limits_set.max_array_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the maximum length of object maps (0 for unlimited).
|
/// Set the maximum length of object maps (0 for unlimited).
|
||||||
@ -171,7 +175,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
pub fn set_max_map_size(&mut self, max_size: usize) -> &mut Self {
|
||||||
self.limits.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
self.limits_set.max_map_size = if max_size == usize::MAX { 0 } else { max_size };
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,7 +184,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn max_map_size(&self) -> usize {
|
pub fn max_map_size(&self) -> usize {
|
||||||
self.limits.max_map_size
|
self.limits_set.max_map_size
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the module resolution service used by the `Engine`.
|
/// Set the module resolution service used by the `Engine`.
|
||||||
|
@ -67,14 +67,14 @@ impl EvalContext<'_, '_, '_, '_, '_, '_> {
|
|||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
expr: &Expression,
|
expr: &Expression,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
self.engine.eval_expr(
|
self.engine().eval_expr(
|
||||||
scope,
|
scope,
|
||||||
self.mods,
|
self.mods,
|
||||||
self.state,
|
self.state,
|
||||||
self.lib,
|
self.namespace(),
|
||||||
self.this_ptr,
|
self.this_ptr,
|
||||||
expr.expr(),
|
expr.expr(),
|
||||||
self.level,
|
self.call_level(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1747,7 +1747,7 @@ pub fn lex<'a, 'e>(
|
|||||||
engine,
|
engine,
|
||||||
state: TokenizeState {
|
state: TokenizeState {
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_string_size: engine.limits.max_string_size,
|
max_string_size: engine.limits_set.max_string_size,
|
||||||
#[cfg(feature = "unchecked")]
|
#[cfg(feature = "unchecked")]
|
||||||
max_string_size: 0,
|
max_string_size: 0,
|
||||||
non_unary: false,
|
non_unary: false,
|
||||||
|
@ -98,12 +98,12 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
|
|||||||
TypeId::of::<FnPtr>(),
|
TypeId::of::<FnPtr>(),
|
||||||
TypeId::of::<INT>(),
|
TypeId::of::<INT>(),
|
||||||
],
|
],
|
||||||
move |engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
|
move |context, args| {
|
||||||
let fp = std::mem::take(args[1]).cast::<FnPtr>();
|
let fp = std::mem::take(args[1]).cast::<FnPtr>();
|
||||||
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(engine, lib, Some(this_ptr), [value])
|
fp.call_dynamic(context, Some(this_ptr), [value])
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#![cfg(not(feature = "no_function"))]
|
#![cfg(not(feature = "no_function"))]
|
||||||
use rhai::{Dynamic, Engine, EvalAltResult, FnPtr, Module, ParseErrorType, RegisterFn, Scope, INT};
|
use rhai::{Engine, EvalAltResult, FnPtr, ParseErrorType, RegisterFn, Scope, INT};
|
||||||
use std::any::TypeId;
|
use std::any::TypeId;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::mem::take;
|
use std::mem::take;
|
||||||
@ -16,9 +16,9 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine.register_raw_fn(
|
engine.register_raw_fn(
|
||||||
"call_with_arg",
|
"call_with_arg",
|
||||||
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
&[TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|
||||||
|engine: &Engine, lib: &Module, args: &mut [&mut Dynamic]| {
|
|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(engine, lib, None, [std::mem::take(args[1])])
|
fn_ptr.call_dynamic(context, None, [std::mem::take(args[1])])
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -135,10 +135,10 @@ fn test_closures() -> Result<(), Box<EvalAltResult>> {
|
|||||||
engine.register_raw_fn(
|
engine.register_raw_fn(
|
||||||
"custom_call",
|
"custom_call",
|
||||||
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
&[TypeId::of::<INT>(), TypeId::of::<FnPtr>()],
|
||||||
|engine: &Engine, module: &Module, args: &mut [&mut Dynamic]| {
|
|context, args| {
|
||||||
let func = take(args[1]).cast::<FnPtr>();
|
let func = take(args[1]).cast::<FnPtr>();
|
||||||
|
|
||||||
func.call_dynamic(engine, module, None, [])
|
func.call_dynamic(context, None, [])
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -259,7 +259,6 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let mut ast = engine.compile(
|
let mut ast = engine.compile(
|
||||||
r#"
|
r#"
|
||||||
let test = "hello";
|
let test = "hello";
|
||||||
|
|
||||||
|x| test + x
|
|x| test + x
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
@ -271,7 +270,7 @@ fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
|||||||
ast.retain_functions(|_, _, _| true);
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
// Closure 'f' captures: the engine, the AST, and the curried function pointer
|
||||||
let f = move |x: INT| fn_ptr.call_dynamic(&engine, ast, None, [x.into()]);
|
let f = move |x: INT| fn_ptr.call_dynamic((&engine, ast.as_ref()).into(), None, [x.into()]);
|
||||||
|
|
||||||
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user