Merge branch 'plugins' into plugins_dev
This commit is contained in:
commit
a72f797da1
@ -9,6 +9,7 @@ Bug fixes
|
|||||||
|
|
||||||
* `Engine::compile_expression`, `Engine::eval_expression` etc. no longer parse anonymous functions and closures.
|
* `Engine::compile_expression`, `Engine::eval_expression` etc. no longer parse anonymous functions and closures.
|
||||||
* Imported modules now work inside closures.
|
* Imported modules now work inside closures.
|
||||||
|
* Closures that capture now work under `no_object`.
|
||||||
|
|
||||||
|
|
||||||
Version 0.18.2
|
Version 0.18.2
|
||||||
|
@ -23,7 +23,7 @@ The Rhai Scripting Language
|
|||||||
1. [Hello World in Rhai - Evaluate a Script](engine/hello-world.md)
|
1. [Hello World in Rhai - Evaluate a Script](engine/hello-world.md)
|
||||||
2. [Compile to AST for Repeated Evaluations](engine/compile.md)
|
2. [Compile to AST for Repeated Evaluations](engine/compile.md)
|
||||||
3. [Call a Rhai Function from Rust](engine/call-fn.md)
|
3. [Call a Rhai Function from Rust](engine/call-fn.md)
|
||||||
4. [Create a Rust Anonymous Function from a Rhai Function](engine/func.md)
|
4. [Create a Rust Closure from a Rhai Function](engine/func.md)
|
||||||
5. [Evaluate Expressions Only](engine/expressions.md)
|
5. [Evaluate Expressions Only](engine/expressions.md)
|
||||||
6. [Raw Engine](engine/raw.md)
|
6. [Raw Engine](engine/raw.md)
|
||||||
4. [Extend Rhai with Rust](rust/index.md)
|
4. [Extend Rhai with Rust](rust/index.md)
|
||||||
@ -106,6 +106,7 @@ The Rhai Scripting Language
|
|||||||
2. [Loadable Configuration](patterns/config.md)
|
2. [Loadable Configuration](patterns/config.md)
|
||||||
3. [Control Layer](patterns/control.md)
|
3. [Control Layer](patterns/control.md)
|
||||||
4. [Singleton Command](patterns/singleton.md)
|
4. [Singleton Command](patterns/singleton.md)
|
||||||
|
5. [One Engine Instance Per Call](patterns/parallel.md)
|
||||||
2. [Capture Scope for Function Call](language/fn-capture.md)
|
2. [Capture Scope for Function Call](language/fn-capture.md)
|
||||||
3. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
3. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
||||||
4. [Script Optimization](engine/optimize/index.md)
|
4. [Script Optimization](engine/optimize/index.md)
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
Create a Rust Anonymous Function from a Rhai Function
|
Create a Rust Closure from a Rhai Function
|
||||||
===================================================
|
=========================================
|
||||||
|
|
||||||
{{#include ../links.md}}
|
{{#include ../links.md}}
|
||||||
|
|
||||||
It is possible to further encapsulate a script in Rust such that it becomes a normal Rust function.
|
It is possible to further encapsulate a script in Rust such that it becomes a normal Rust function.
|
||||||
|
|
||||||
Such an _anonymous function_ is basically a boxed closure, very useful as call-back functions.
|
Such a _closure_ is very useful as call-back functions.
|
||||||
|
|
||||||
Creating them is accomplished via the `Func` trait which contains `create_from_script`
|
Creating them is accomplished via the `Func` trait which contains `create_from_script`
|
||||||
(as well as its companion method `create_from_ast`):
|
(as well as its companion method `create_from_ast`):
|
||||||
@ -30,7 +30,7 @@ let func = Func::<(i64, String), bool>::create_from_script(
|
|||||||
"calc" // the entry-point function name
|
"calc" // the entry-point function name
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
func(123, "hello".to_string())? == false; // call the anonymous function
|
func(123, "hello".to_string())? == false; // call the closure
|
||||||
|
|
||||||
schedule_callback(func); // pass it as a callback to another function
|
schedule_callback(func); // pass it as a callback to another function
|
||||||
|
|
||||||
|
@ -35,7 +35,8 @@ The actual implementation de-sugars to:
|
|||||||
|
|
||||||
1. Keeping track of what variables are accessed inside the anonymous function,
|
1. Keeping track of what variables are accessed inside the anonymous function,
|
||||||
|
|
||||||
2. If a variable is not defined within the anonymous function's scope, it is looked up _outside_ the function and in the current execution scope - where the anonymous function is created.
|
2. If a variable is not defined within the anonymous function's scope, it is looked up _outside_ the function and
|
||||||
|
in the current execution scope - where the anonymous function is created.
|
||||||
|
|
||||||
3. The variable is added to the parameters list of the anonymous function, at the front.
|
3. The variable is added to the parameters list of the anonymous function, at the front.
|
||||||
|
|
||||||
@ -43,7 +44,8 @@ The actual implementation de-sugars to:
|
|||||||
|
|
||||||
An [anonymous function] which captures an external variable is the only way to create a reference-counted shared value in Rhai.
|
An [anonymous function] which captures an external variable is the only way to create a reference-counted shared value in Rhai.
|
||||||
|
|
||||||
5. The shared value is then [curried][currying] into the [function pointer] itself, essentially carrying a reference to that shared value and inserting it into future calls of the function.
|
5. The shared value is then [curried][currying] into the [function pointer] itself, essentially carrying a reference to that shared value
|
||||||
|
and inserting it into future calls of the function.
|
||||||
|
|
||||||
This process is called _Automatic Currying_, and is the mechanism through which Rhai simulates normal closures.
|
This process is called _Automatic Currying_, and is the mechanism through which Rhai simulates normal closures.
|
||||||
|
|
||||||
|
@ -75,3 +75,17 @@ let map = engine.parse_json(&new_json, false)?;
|
|||||||
|
|
||||||
map.len() == 2; // 'map' contains two properties: 'a' and 'b'
|
map.len() == 2; // 'map' contains two properties: 'a' and 'b'
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Use `serde` to Serialize/Deserialize to/from JSON
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
Remember, `Engine::parse_json` is nothing more than a _cheap_ alternative to true JSON parsing.
|
||||||
|
|
||||||
|
If correctness is needed, or for more configuration possibilities, turn on the [`serde`][features]
|
||||||
|
feature to pull in the [`serde`](https://crates.io/crates/serde) crate which enables
|
||||||
|
serialization and deserialization to/from multiple formats, including JSON.
|
||||||
|
|
||||||
|
Beware, though... the [`serde`](https://crates.io/crates/serde) crate is quite heavy.
|
||||||
|
|
||||||
|
See _[Serialization/Deserialization of `Dynamic` with `serde`][`serde`]_ for more details.
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
|
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
|
||||||
[package]: {{rootUrl}}/rust/packages/index.md
|
[package]: {{rootUrl}}/rust/packages/index.md
|
||||||
[packages]: {{rootUrl}}/rust/packages/index.md
|
[packages]: {{rootUrl}}/rust/packages/index.md
|
||||||
|
[custom package]: {{rootUrl}}/rust/packages/create.md
|
||||||
|
[custom packages]: {{rootUrl}}/rust/packages/create.md
|
||||||
[`Scope`]: {{rootUrl}}/rust/scope.md
|
[`Scope`]: {{rootUrl}}/rust/scope.md
|
||||||
[`serde`]: {{rootUrl}}/rust/serde.md
|
[`serde`]: {{rootUrl}}/rust/serde.md
|
||||||
|
|
||||||
|
70
doc/src/patterns/parallel.md
Normal file
70
doc/src/patterns/parallel.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
One Engine Instance Per Call
|
||||||
|
===========================
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
|
||||||
|
Usage Scenario
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* A system where scripts are called a _lot_, in tight loops or in parallel.
|
||||||
|
|
||||||
|
* Keeping a global [`Engine`] instance is sub-optimal due to contention and locking.
|
||||||
|
|
||||||
|
* Scripts need to be executed independently from each other, perhaps concurrently.
|
||||||
|
|
||||||
|
* Scripts are used to [create Rust closure][`Func`] that are stored and may be called at any time, perhaps concurrently.
|
||||||
|
In this case, the [`Engine`] instance is usually moved into the closure itself.
|
||||||
|
|
||||||
|
|
||||||
|
Key Concepts
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Create a single instance of each standard [package] required. To duplicate `Engine::new`, create a [`StandardPackage`]({{rootUrl}}/rust/packages/builtin.md).
|
||||||
|
|
||||||
|
* Gather up all common custom functions into a [custom package].
|
||||||
|
|
||||||
|
* Store a global `AST` for use with all engines.
|
||||||
|
|
||||||
|
* Always use `Engine::new_raw` to create a [raw `Engine`], instead of `Engine::new` which is _much_ more expensive.
|
||||||
|
A [raw `Engine`] is _extremely_ cheap to create.
|
||||||
|
|
||||||
|
Loading the [`StandardPackage`]({{rootUrl}}/rust/packages/builtin.md) into a [raw `Engine`] via `Engine::load_package` is essentially the same as `Engine::new`.
|
||||||
|
But because packages are shared, loading an existing package is _much cheaper_ than registering all the functions one by one.
|
||||||
|
|
||||||
|
* Load the required packages into the [raw `Engine`] via `Engine::load_package`, using `Package::get` to obtain a shared copy.
|
||||||
|
|
||||||
|
|
||||||
|
Examples
|
||||||
|
--------
|
||||||
|
|
||||||
|
```rust
|
||||||
|
use rhai::packages::{Package, StandardPackage};
|
||||||
|
|
||||||
|
let ast = /* ... some AST ... */;
|
||||||
|
let std_pkg = StandardPackage::new();
|
||||||
|
let custom_pkg = MyCustomPackage::new();
|
||||||
|
|
||||||
|
let make_call = |x: i64| -> Result<(), Box<EvalAltResult>> {
|
||||||
|
// Create a raw Engine - extremely cheap.
|
||||||
|
let mut engine = Engine::new_raw();
|
||||||
|
|
||||||
|
// Load packages - cheap.
|
||||||
|
engine.load_package(std_pkg.get());
|
||||||
|
engine.load_package(custom_pkg.get());
|
||||||
|
|
||||||
|
// Create custom scope - cheap.
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
|
// Push variable into scope - relatively cheap.
|
||||||
|
scope.push("x", x);
|
||||||
|
|
||||||
|
// Evaluate script.
|
||||||
|
engine.consume_ast_with_scope(&mut scope, &ast)
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following loop creates 10,000 Engine instances!
|
||||||
|
for x in 0..10_000 {
|
||||||
|
make_call(x)?;
|
||||||
|
}
|
||||||
|
```
|
@ -5,6 +5,14 @@ Create a Custom Package
|
|||||||
|
|
||||||
Sometimes specific functionalities are needed, so custom packages can be created.
|
Sometimes specific functionalities are needed, so custom packages can be created.
|
||||||
|
|
||||||
|
A custom package is a convenient means to gather up a number of functions for later use.
|
||||||
|
An [`Engine`] only needs to `Engine::load_package` the custom package once to gain access
|
||||||
|
to the entire set of functions within.
|
||||||
|
|
||||||
|
Loading a package into an [`Engine`] is functionally equivalent to calling `Engine::register_fn` etc.
|
||||||
|
on _each_ of the functions inside the package. But because packages are _shared_, loading an existing
|
||||||
|
package is _much_ cheaper than registering all the functions one by one.
|
||||||
|
|
||||||
The macro `rhai::def_package!` is used to create a new custom package.
|
The macro `rhai::def_package!` is used to create a new custom package.
|
||||||
|
|
||||||
|
|
||||||
|
@ -6,15 +6,16 @@ Serialization and Deserialization of `Dynamic` with `serde`
|
|||||||
Rhai's [`Dynamic`] type supports serialization and deserialization by [`serde`](https://crates.io/crates/serde)
|
Rhai's [`Dynamic`] type supports serialization and deserialization by [`serde`](https://crates.io/crates/serde)
|
||||||
via the [`serde`][features] feature.
|
via the [`serde`][features] feature.
|
||||||
|
|
||||||
A [`Dynamic`] can be seamlessly converted to and from a type that implements `serde::Serialize` and/or
|
A [`Dynamic`] can be seamlessly converted to and from a type that implements
|
||||||
`serde::Deserialize`.
|
[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) and/or
|
||||||
|
[`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html).
|
||||||
|
|
||||||
|
|
||||||
Serialization
|
Serialization
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
The function `rhai::ser::to_dynamic` automatically converts any Rust type that implements `serde::Serialize`
|
The function `rhai::ser::to_dynamic` automatically converts any Rust type that implements
|
||||||
into a [`Dynamic`].
|
[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) into a [`Dynamic`].
|
||||||
|
|
||||||
This is usually not necessary because using [`Dynamic::from`][`Dynamic`] is much easier and is essentially
|
This is usually not necessary because using [`Dynamic::from`][`Dynamic`] is much easier and is essentially
|
||||||
the same thing. The only difference is treatment for integer values. `Dynamic::from` will keep the different
|
the same thing. The only difference is treatment for integer values. `Dynamic::from` will keep the different
|
||||||
@ -64,7 +65,7 @@ Deserialization
|
|||||||
---------------
|
---------------
|
||||||
|
|
||||||
The function `rhai::de::from_dynamic` automatically converts a [`Dynamic`] value into any Rust type
|
The function `rhai::de::from_dynamic` automatically converts a [`Dynamic`] value into any Rust type
|
||||||
that implements `serde::Deserialize`.
|
that implements [`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html).
|
||||||
|
|
||||||
In particular, [object maps] are converted into Rust `struct`'s (or any type that is marked as
|
In particular, [object maps] are converted into Rust `struct`'s (or any type that is marked as
|
||||||
a `serde` map) while [arrays] are converted into Rust `Vec`'s (or any type that is marked
|
a `serde` map) while [arrays] are converted into Rust `Vec`'s (or any type that is marked
|
||||||
@ -102,3 +103,13 @@ let result: Dynamic = engine.eval(r#"
|
|||||||
// Convert the 'Dynamic' object map into 'MyStruct'
|
// Convert the 'Dynamic' object map into 'MyStruct'
|
||||||
let x: MyStruct = from_dynamic(&result)?;
|
let x: MyStruct = from_dynamic(&result)?;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Lighter Alternative
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
The [`serde`](https://crates.io/crates/serde) crate is quite heavy.
|
||||||
|
|
||||||
|
If only _simple_ JSON parsing (i.e. only deserialization) of a hash object into a Rhai [object map] is required,
|
||||||
|
the [`Engine::parse_json`]({{rootUrl}}/language/json.md}}) method is available as a _cheap_ alternative,
|
||||||
|
but it does not provide the same level of correctness, nor are there any configurable options.
|
||||||
|
@ -9,5 +9,5 @@ A number of traits, under the `rhai::` module namespace, provide additional func
|
|||||||
| ------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------- |
|
||||||
| `RegisterFn` | Trait for registering functions | `register_fn` |
|
| `RegisterFn` | Trait for registering functions | `register_fn` |
|
||||||
| `RegisterResultFn` | Trait for registering fallible functions returning `Result<Dynamic, Box<EvalAltResult>>` | `register_result_fn` |
|
| `RegisterResultFn` | Trait for registering fallible functions returning `Result<Dynamic, Box<EvalAltResult>>` | `register_result_fn` |
|
||||||
| `Func` | Trait for creating anonymous functions from script | `create_from_ast`, `create_from_script` |
|
| `Func` | Trait for creating Rust closures from script | `create_from_ast`, `create_from_script` |
|
||||||
| `ModuleResolver` | Trait implemented by module resolution services | `resolve` |
|
| `ModuleResolver` | Trait implemented by module resolution services | `resolve` |
|
||||||
|
@ -340,6 +340,7 @@ pub fn get_script_function_by_signature<'a>(
|
|||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Limits {
|
pub struct Limits {
|
||||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||||
///
|
///
|
||||||
|
@ -12,11 +12,11 @@ use crate::scope::Scope;
|
|||||||
|
|
||||||
use crate::stdlib::{boxed::Box, string::ToString};
|
use crate::stdlib::{boxed::Box, string::ToString};
|
||||||
|
|
||||||
/// Trait to create a Rust anonymous function from a script.
|
/// Trait to create a Rust closure from a script.
|
||||||
pub trait Func<ARGS, RET> {
|
pub trait Func<ARGS, RET> {
|
||||||
type Output;
|
type Output;
|
||||||
|
|
||||||
/// Create a Rust anonymous function from an `AST`.
|
/// Create a Rust closure from an `AST`.
|
||||||
/// The `Engine` and `AST` are consumed and basically embedded into the closure.
|
/// The `Engine` and `AST` are consumed and basically embedded into the closure.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -47,7 +47,7 @@ pub trait Func<ARGS, RET> {
|
|||||||
/// # }
|
/// # }
|
||||||
fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output;
|
fn create_from_ast(self, ast: AST, entry_point: &str) -> Self::Output;
|
||||||
|
|
||||||
/// Create a Rust anonymous function from a script.
|
/// Create a Rust closure from a script.
|
||||||
/// The `Engine` is consumed and basically embedded into the closure.
|
/// The `Engine` is consumed and basically embedded into the closure.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -3167,6 +3167,8 @@ fn make_curry_from_externals(
|
|||||||
let num_externals = externals.len();
|
let num_externals = externals.len();
|
||||||
let mut args: StaticVec<_> = Default::default();
|
let mut args: StaticVec<_> = Default::default();
|
||||||
|
|
||||||
|
args.push(fn_expr);
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals.iter().for_each(|(var_name, pos)| {
|
externals.iter().for_each(|(var_name, pos)| {
|
||||||
args.push(Expr::Variable(Box::new((
|
args.push(Expr::Variable(Box::new((
|
||||||
@ -3182,9 +3184,9 @@ fn make_curry_from_externals(
|
|||||||
args.push(Expr::Variable(Box::new(((var_name, pos), None, 0, None))));
|
args.push(Expr::Variable(Box::new(((var_name, pos), None, 0, None))));
|
||||||
});
|
});
|
||||||
|
|
||||||
let hash = calc_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals, empty());
|
let hash = calc_fn_hash(empty(), KEYWORD_FN_PTR_CURRY, num_externals + 1, empty());
|
||||||
|
|
||||||
let fn_call = Expr::FnCall(Box::new((
|
let expr = Expr::FnCall(Box::new((
|
||||||
(KEYWORD_FN_PTR_CURRY.into(), false, false, pos),
|
(KEYWORD_FN_PTR_CURRY.into(), false, false, pos),
|
||||||
None,
|
None,
|
||||||
hash,
|
hash,
|
||||||
@ -3192,8 +3194,6 @@ fn make_curry_from_externals(
|
|||||||
None,
|
None,
|
||||||
)));
|
)));
|
||||||
|
|
||||||
let expr = Expr::Dot(Box::new((fn_expr, fn_call, pos)));
|
|
||||||
|
|
||||||
// If there are captured variables, convert the entire expression into a statement block,
|
// If there are captured variables, convert the entire expression into a statement block,
|
||||||
// then insert the relevant `Share` statements.
|
// then insert the relevant `Share` statements.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
@ -200,7 +200,7 @@ type MyType = Rc<RefCell<INT>>;
|
|||||||
#[test]
|
#[test]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
fn test_closure_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
fn test_closures_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Register API on MyType
|
// Register API on MyType
|
||||||
@ -250,3 +250,30 @@ fn test_closure_shared_obj() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
fn test_closures_external() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let engine = Engine::new();
|
||||||
|
|
||||||
|
let mut ast = engine.compile(
|
||||||
|
r#"
|
||||||
|
let test = "hello";
|
||||||
|
|
||||||
|
|x| test + x
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Save the function pointer together with captured variables
|
||||||
|
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
|
||||||
|
|
||||||
|
// Get rid of the script, retaining only functions
|
||||||
|
ast.retain_functions(|_, _, _| true);
|
||||||
|
|
||||||
|
// 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()]);
|
||||||
|
|
||||||
|
assert_eq!(f(42)?.as_str(), Ok("hello42"));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
33
tests/packages.rs
Normal file
33
tests/packages.rs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
use rhai::{Engine, EvalAltResult, INT, Scope};
|
||||||
|
use rhai::packages::{Package, StandardPackage};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_packages() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
let e = Engine::new();
|
||||||
|
let ast = e.compile("x")?;
|
||||||
|
let std_pkg = StandardPackage::new();
|
||||||
|
|
||||||
|
let make_call = |x: INT| -> Result<INT, Box<EvalAltResult>> {
|
||||||
|
// Create a raw Engine - extremely cheap.
|
||||||
|
let mut engine = Engine::new_raw();
|
||||||
|
|
||||||
|
// Load packages - cheap.
|
||||||
|
engine.load_package(std_pkg.get());
|
||||||
|
|
||||||
|
// Create custom scope - cheap.
|
||||||
|
let mut scope = Scope::new();
|
||||||
|
|
||||||
|
// Push variable into scope - relatively cheap.
|
||||||
|
scope.push("x", x);
|
||||||
|
|
||||||
|
// Evaluate script.
|
||||||
|
engine.eval_ast_with_scope::<INT>(&mut scope, &ast)
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following loop creates 10,000 Engine instances!
|
||||||
|
for x in 0..10_000 {
|
||||||
|
assert_eq!(make_call(x)?, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user