Change Option<usize> to usize for variable resolver index.
This commit is contained in:
parent
fd5a932611
commit
e343bcfa8f
@ -121,6 +121,7 @@ The Rhai Scripting Language
|
|||||||
5. [Multi-Layer Functions](patterns/multi-layer.md)
|
5. [Multi-Layer Functions](patterns/multi-layer.md)
|
||||||
6. [One Engine Instance Per Call](patterns/parallel.md)
|
6. [One Engine Instance Per Call](patterns/parallel.md)
|
||||||
7. [Scriptable Event Handler with State](patterns/events.md)
|
7. [Scriptable Event Handler with State](patterns/events.md)
|
||||||
|
8. [Dynamic Constants Provider](patterns/dynamic-const.md)
|
||||||
9. [Advanced Topics](advanced.md)
|
9. [Advanced Topics](advanced.md)
|
||||||
1. [Capture Scope for Function Call](language/fn-capture.md)
|
1. [Capture Scope for Function Call](language/fn-capture.md)
|
||||||
2. [Low-Level API](rust/register-raw.md)
|
2. [Low-Level API](rust/register-raw.md)
|
||||||
|
@ -3,14 +3,4 @@ Advanced Topics
|
|||||||
|
|
||||||
{{#include links.md}}
|
{{#include links.md}}
|
||||||
|
|
||||||
This section covers advanced features such as:
|
This section covers advanced features of the Rhai [`Engine`].
|
||||||
|
|
||||||
* [Advanced patterns]({{rootUrl}}/patterns/index.md) in using Rhai.
|
|
||||||
|
|
||||||
* [Capture the calling scope]({{rootUrl}}/language/fn-capture.md) in a function call.
|
|
||||||
|
|
||||||
* [`serde`] integration.
|
|
||||||
|
|
||||||
* Low-level [function registration API]({{rootUrl}}/rust/register-raw.md)
|
|
||||||
|
|
||||||
* [Domain-Specific Languages][DSL].
|
|
||||||
|
@ -122,7 +122,7 @@ where:
|
|||||||
|
|
||||||
* `context: &mut EvalContext` - mutable reference to the current evaluation _context_ (**do not touch**) which exposes the following fields:
|
* `context: &mut EvalContext` - mutable reference to the current evaluation _context_ (**do not touch**) which exposes the following fields:
|
||||||
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
||||||
* `context.namespace(): &Module` - reference to the current _global namespace_ containing all script-defined functions.
|
* `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions.
|
||||||
* `context.call_level(): usize` - the current nesting level of function calls.
|
* `context.call_level(): usize` - the current nesting level of function calls.
|
||||||
|
|
||||||
* `inputs: &[Expression]` - a list of input expression trees.
|
* `inputs: &[Expression]` - a list of input expression trees.
|
||||||
|
@ -16,7 +16,7 @@ To do so, provide a closure to the [`Engine`] via the [`Engine::on_var`] method:
|
|||||||
let mut engine = Engine::new();
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
// Register a variable resolver.
|
// Register a variable resolver.
|
||||||
engine.on_var(|name, index, engine, scope, lib| {
|
engine.on_var(|name, index, scope, context| {
|
||||||
match name {
|
match name {
|
||||||
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
|
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
|
||||||
// Override a variable - make it not found even if it exists!
|
// Override a variable - make it not found even if it exists!
|
||||||
@ -50,26 +50,23 @@ Function Signature
|
|||||||
|
|
||||||
The function signature passed to `Engine::on_var` takes the following form:
|
The function signature passed to `Engine::on_var` takes the following form:
|
||||||
|
|
||||||
> `Fn(name: &str, index: Option<usize>, scope: &Scope, context: &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>> + 'static`
|
> `Fn(name: &str, index: usize, scope: &Scope, context: &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>> + 'static`
|
||||||
|
|
||||||
where:
|
where:
|
||||||
|
|
||||||
* `name: &str` - variable name.
|
* `name: &str` - variable name.
|
||||||
|
|
||||||
* `index: Option<usize>` - an offset from the bottom of the current [`Scope`] that the variable is supposed to reside.
|
* `index: usize` - an offset from the bottom of the current [`Scope`] that the variable is supposed to reside.
|
||||||
Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`.
|
Offsets start from 1, with 1 meaning the last variable in the current [`Scope`]. Essentially the correct variable is at position `scope.len() - index`.
|
||||||
Notice that, if there was an [`eval`] statement before the current statement, new variables may have been introduced and this index may be incorrect.
|
|
||||||
Therefore, this index is for reference only. It should not be relied upon.
|
|
||||||
|
|
||||||
If `index` is `None`, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed.
|
If `index` is zero, then there is no pre-calculated offset position and a search through the current [`Scope`] must be performed.
|
||||||
|
|
||||||
* `scope : &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position.
|
* `scope : &Scope` - reference to the current [`Scope`] containing all variables up to the current evaluation position.
|
||||||
|
|
||||||
* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields:
|
* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields:
|
||||||
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
* `context.engine(): &Engine` - reference to the current [`Engine`].
|
||||||
* `context.namespace(): &Module` - reference to the current _global namespace_ containing all script-defined functions.
|
* `context.namespace(): &Module` - reference to the current _global namespace_ (as a [module]) containing all script-defined functions.
|
||||||
* `context.call_level(): usize` - the current nesting level of function calls.
|
* `context.call_level(): usize` - the current nesting level of function calls.
|
||||||
|
|
||||||
The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where `Ok(None)` indicates that the normal
|
The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where `Ok(None)` indicates that the normal
|
||||||
variable resolution process should continue.
|
variable resolution process should continue.
|
||||||
|
|
||||||
|
56
doc/src/patterns/dynamic-const.md
Normal file
56
doc/src/patterns/dynamic-const.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
Dynamic Constants Provider
|
||||||
|
=========================
|
||||||
|
|
||||||
|
{{#include ../links.md}}
|
||||||
|
|
||||||
|
|
||||||
|
Usage Scenario
|
||||||
|
--------------
|
||||||
|
|
||||||
|
* A system has a _large_ number of constants, but only a minor set will be used by any script.
|
||||||
|
|
||||||
|
* The system constants are expensive to load.
|
||||||
|
|
||||||
|
* The system constants set is too massive to push into a custom [`Scope`].
|
||||||
|
|
||||||
|
* The values of system constants are volatile and call-dependent.
|
||||||
|
|
||||||
|
|
||||||
|
Key Concepts
|
||||||
|
------------
|
||||||
|
|
||||||
|
* Use a [variable resolver] to intercept variable access.
|
||||||
|
|
||||||
|
* Only load a variable when it is being used.
|
||||||
|
|
||||||
|
* Perform a lookup based on variable name, and provide the correct data value.
|
||||||
|
|
||||||
|
* May even perform back-end network access or look up the latest value from a database.
|
||||||
|
|
||||||
|
|
||||||
|
Implementation
|
||||||
|
--------------
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let mut engine = Engine::new();
|
||||||
|
|
||||||
|
// Create shared data provider.
|
||||||
|
// Assume that Provider::get(&str) -> Option<value> gets a system constant.
|
||||||
|
let provider: Arc<Provider> = get_data_provider();
|
||||||
|
|
||||||
|
// Clone the shared provider
|
||||||
|
let db = provider.clone();
|
||||||
|
|
||||||
|
// Register a variable resolver.
|
||||||
|
// Move the shared provider into the closure.
|
||||||
|
engine.on_var(move |name, _, _, _| Ok(db.get(name).map(Dynamic::from)));
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
Values are Constants
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
All values provided by a [variable resolver] are _constants_ due to their dynamic nature.
|
||||||
|
They cannot be assigned to.
|
||||||
|
|
||||||
|
In order to change values in an external system, register a dedicated API for that purpose.
|
@ -1721,12 +1721,7 @@ impl Engine {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn on_var(
|
pub fn on_var(
|
||||||
&mut self,
|
&mut self,
|
||||||
callback: impl Fn(
|
callback: impl Fn(&str, usize, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
||||||
&str,
|
|
||||||
Option<usize>,
|
|
||||||
&Scope,
|
|
||||||
&EvalContext,
|
|
||||||
) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
|
||||||
+ SendSync
|
+ SendSync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
|
@ -745,7 +745,7 @@ impl Engine {
|
|||||||
this_ptr,
|
this_ptr,
|
||||||
level: 0,
|
level: 0,
|
||||||
};
|
};
|
||||||
if let Some(result) = resolve_var(name, index.map(|v| v.get()), scope, &context)
|
if let Some(result) = resolve_var(name, index.map_or(0, |v| v.get()), scope, &context)
|
||||||
.map_err(|err| err.fill_position(*pos))?
|
.map_err(|err| err.fill_position(*pos))?
|
||||||
{
|
{
|
||||||
return Ok((result.into(), name, ScopeEntryType::Constant, *pos));
|
return Ok((result.into(), name, ScopeEntryType::Constant, *pos));
|
||||||
|
@ -224,13 +224,13 @@ pub type Callback<T, R> = Box<dyn Fn(&T) -> R + Send + Sync + 'static>;
|
|||||||
/// A standard callback function.
|
/// A standard callback function.
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
pub type OnVarCallback = Box<
|
pub type OnVarCallback = Box<
|
||||||
dyn Fn(&str, Option<usize>, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
dyn Fn(&str, usize, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
>;
|
>;
|
||||||
/// A standard callback function.
|
/// A standard callback function.
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
pub type OnVarCallback = Box<
|
pub type OnVarCallback = Box<
|
||||||
dyn Fn(&str, Option<usize>, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
dyn Fn(&str, usize, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
||||||
+ Send
|
+ Send
|
||||||
+ Sync
|
+ Sync
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
Loading…
Reference in New Issue
Block a user