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)
|
||||
6. [One Engine Instance Per Call](patterns/parallel.md)
|
||||
7. [Scriptable Event Handler with State](patterns/events.md)
|
||||
8. [Dynamic Constants Provider](patterns/dynamic-const.md)
|
||||
9. [Advanced Topics](advanced.md)
|
||||
1. [Capture Scope for Function Call](language/fn-capture.md)
|
||||
2. [Low-Level API](rust/register-raw.md)
|
||||
|
@ -3,14 +3,4 @@ Advanced Topics
|
||||
|
||||
{{#include links.md}}
|
||||
|
||||
This section covers advanced features such as:
|
||||
|
||||
* [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].
|
||||
This section covers advanced features of the Rhai [`Engine`].
|
||||
|
@ -122,7 +122,7 @@ where:
|
||||
|
||||
* `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.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.
|
||||
|
||||
* `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();
|
||||
|
||||
// Register a variable resolver.
|
||||
engine.on_var(|name, index, engine, scope, lib| {
|
||||
engine.on_var(|name, index, scope, context| {
|
||||
match name {
|
||||
"MYSTIC_NUMBER" => Ok(Some((42 as INT).into())),
|
||||
// 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:
|
||||
|
||||
> `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:
|
||||
|
||||
* `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`.
|
||||
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.
|
||||
|
||||
* `context: &EvalContext` - reference to the current evaluation _context_, which exposes the following fields:
|
||||
* `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.
|
||||
|
||||
The return value is `Result<Option<Dynamic>, Box<EvalAltResult>>` where `Ok(None)` indicates that the normal
|
||||
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)]
|
||||
pub fn on_var(
|
||||
&mut self,
|
||||
callback: impl Fn(
|
||||
&str,
|
||||
Option<usize>,
|
||||
&Scope,
|
||||
&EvalContext,
|
||||
) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
||||
callback: impl Fn(&str, usize, &Scope, &EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
|
||||
+ SendSync
|
||||
+ 'static,
|
||||
) -> &mut Self {
|
||||
|
@ -745,7 +745,7 @@ impl Engine {
|
||||
this_ptr,
|
||||
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))?
|
||||
{
|
||||
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.
|
||||
#[cfg(not(feature = "sync"))]
|
||||
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,
|
||||
>;
|
||||
/// A standard callback function.
|
||||
#[cfg(feature = "sync")]
|
||||
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
|
||||
+ Sync
|
||||
+ 'static,
|
||||
|
Loading…
Reference in New Issue
Block a user