Allow NativeCallContext in function arguments.
This commit is contained in:
@@ -17,11 +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 |
|
||||
| `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_ |
|
||||
| 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]? Not available under [`no_function`]. |
|
||||
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
|
||||
|
||||
|
||||
Examples
|
||||
|
@@ -75,3 +75,76 @@ fn main() {
|
||||
register_exported_fn!(engine, "+", double_and_divide);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
`NativeCallContext` Parameter
|
||||
----------------------------
|
||||
|
||||
If the _first_ parameter of a function is of type `rhai::NativeCallContext`, then it is treated
|
||||
specially by the plugins system.
|
||||
|
||||
`NativeCallContext` is a type that encapsulates the current _native call context_ and exposes the following:
|
||||
|
||||
* `NativeCallContext::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`].
|
||||
|
||||
* `NativeCallContext::namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
|
||||
|
||||
This first parameter, if exists, will be stripped before all other processing. It is _virtual_.
|
||||
Most importantly, it does _not_ count as a parameter to the function and there is no need to provide
|
||||
this argument when calling the function in Rhai.
|
||||
|
||||
The native call context can be used to call a [function pointer] or [closure] that has been passed
|
||||
as a parameter to the function, thereby implementing a _callback_:
|
||||
|
||||
```rust
|
||||
use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult};
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_fn(return_raw)]
|
||||
pub fn greet(context: NativeCallContext, callback: FnPtr)
|
||||
-> Result<Dynamic, Box<EvalAltResult>>
|
||||
{
|
||||
// Call the callback closure with the current context
|
||||
// to obtain the name to greet!
|
||||
let name = callback.call_dynamic(context, None, [])?;
|
||||
Ok(format!("hello, {}!", name).into())
|
||||
}
|
||||
```
|
||||
|
||||
The native call context is also useful in another scenario: protecting a function from malicious scripts.
|
||||
|
||||
```rust
|
||||
use rhai::{Dynamic, INT, Array, NativeCallContext, EvalAltResult, Position};
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
// This function builds an array of arbitrary size, but is protected
|
||||
// against attacks by first checking with the allowed limit set
|
||||
// into the 'Engine'.
|
||||
#[export_fn(return_raw)]
|
||||
pub fn grow(context: NativeCallContext, size: INT)
|
||||
-> Result<Dynamic, Box<EvalAltResult>>
|
||||
{
|
||||
// Make sure the function does not generate a
|
||||
// data structure larger than the allowed limit
|
||||
// for the Engine!
|
||||
if size as usize > context.engine().max_array_size()
|
||||
{
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Size to grow".to_string(),
|
||||
context.engine().max_array_size(),
|
||||
size as usize,
|
||||
Position::none(),
|
||||
).into();
|
||||
}
|
||||
|
||||
let array = Array::new();
|
||||
|
||||
for x in 0..size {
|
||||
array.push(x.into());
|
||||
}
|
||||
|
||||
OK(array.into())
|
||||
}
|
||||
```
|
||||
|
@@ -334,6 +334,85 @@ mod my_module {
|
||||
```
|
||||
|
||||
|
||||
`NativeCallContext` Parameter
|
||||
----------------------------
|
||||
|
||||
If the _first_ parameter of a function is of type `rhai::NativeCallContext`, then it is treated
|
||||
specially by the plugins system.
|
||||
|
||||
`NativeCallContext` is a type that encapsulates the current _native call context_ and exposes the following:
|
||||
|
||||
* `NativeCallContext::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`].
|
||||
|
||||
* `NativeCallContext::namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
|
||||
|
||||
This first parameter, if exists, will be stripped before all other processing. It is _virtual_.
|
||||
Most importantly, it does _not_ count as a parameter to the function and there is no need to provide
|
||||
this argument when calling the function in Rhai.
|
||||
|
||||
The native call context can be used to call a [function pointer] or [closure] that has been passed
|
||||
as a parameter to the function, thereby implementing a _callback_:
|
||||
|
||||
```rust
|
||||
use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult};
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn greet(context: NativeCallContext, callback: FnPtr)
|
||||
-> Result<Dynamic, Box<EvalAltResult>>
|
||||
{
|
||||
// Call the callback closure with the current context
|
||||
// to obtain the name to greet!
|
||||
let name = callback.call_dynamic(context, None, [])?;
|
||||
Ok(format!("hello, {}!", name).into())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The native call context is also useful in another scenario: protecting a function from malicious scripts.
|
||||
|
||||
```rust
|
||||
use rhai::{Dynamic, INT, Array, NativeCallContext, EvalAltResult, Position};
|
||||
use rhai::plugin::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This function builds an array of arbitrary size, but is protected
|
||||
// against attacks by first checking with the allowed limit set
|
||||
// into the 'Engine'.
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn grow(context: NativeCallContext, size: INT)
|
||||
-> Result<Dynamic, Box<EvalAltResult>>
|
||||
{
|
||||
// Make sure the function does not generate a
|
||||
// data structure larger than the allowed limit
|
||||
// for the Engine!
|
||||
if size as usize > context.engine().max_array_size()
|
||||
{
|
||||
return EvalAltResult::ErrorDataTooLarge(
|
||||
"Size to grow".to_string(),
|
||||
context.engine().max_array_size(),
|
||||
size as usize,
|
||||
Position::none(),
|
||||
).into();
|
||||
}
|
||||
|
||||
let array = Array::new();
|
||||
|
||||
for x in 0..size {
|
||||
array.push(x.into());
|
||||
}
|
||||
|
||||
OK(array.into())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
`#[export_module]` Parameters
|
||||
----------------------------
|
||||
|
||||
|
@@ -70,7 +70,7 @@ where:
|
||||
|
||||
* `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`].
|
||||
using [`Engine::call_fn`][`call_fn`], or calling a [function pointer].
|
||||
|
||||
* `context.namespace(): &Module` - the global namespace of script-defined functions, as a [`Module`].
|
||||
|
||||
|
Reference in New Issue
Block a user