Encapsulate register_fn_raw parameters into NativeCallContext.
This commit is contained in:
@@ -17,10 +17,11 @@ Built-in methods
|
||||
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
||||
using a [raw `Engine`]) operate on function pointers:
|
||||
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `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_ |
|
||||
| Function | Parameter(s) | Description |
|
||||
| ---------------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| `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
|
||||
@@ -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.
|
||||
`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,
|
||||
and other necessary arguments.
|
||||
current _native call context_, the `this` pointer, and other necessary arguments.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr, NativeCallContext};
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// 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>>
|
||||
{
|
||||
// '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.
|
||||
// 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
|
||||
@@ -218,3 +218,43 @@ engine.register_raw_fn("super_call",
|
||||
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.
|
||||
|
||||
In particular, a reference to the current `Engine` instance is passed as an argument so the Rust function
|
||||
can also use `Engine` facilities (like evaluating a script).
|
||||
In particular, a the current _native call context_ (in form of the `NativeCallContext` type) is passed as an argument.
|
||||
`NativeCallContext` exposes the current [`Engine`], among others, so the Rust function can also use [`Engine`] facilities
|
||||
(such as evaluating a script).
|
||||
|
||||
```rust
|
||||
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 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.
|
||||
|
||||
// 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:
|
||||
|
||||
> `Fn(engine: &Engine, lib: &Module, args: &mut [&mut Dynamic])`
|
||||
> `-> Result<T, Box<EvalAltResult>> + 'static`
|
||||
> `Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>> + 'static`
|
||||
|
||||
where:
|
||||
|
||||
* `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`].
|
||||
This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`].
|
||||
* `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`].
|
||||
|
||||
* `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.
|
||||
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.
|
||||
|
||||
```rust
|
||||
use rhai::{Engine, Module, Dynamic, FnPtr};
|
||||
use rhai::{Engine, FnPtr};
|
||||
|
||||
let mut engine = Engine::new();
|
||||
|
||||
@@ -118,7 +121,7 @@ engine.register_raw_fn(
|
||||
std::any::TypeId::of::<FnPtr>(),
|
||||
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
|
||||
|
||||
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.
|
||||
// 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])
|
||||
},
|
||||
);
|
||||
|
||||
|
Reference in New Issue
Block a user