5.9 KiB
5.9 KiB
Variable Resolver
{{#include ../links.md}}
By default, Rhai looks up access to [variables] from the enclosing block scope, working its way
outwards until it reaches the top (global) level, then it searches the [Scope
] that is passed into
the Engine::eval
call.
There is a built-in facility for advanced users to hook into the [variable] resolution service and to override its default behavior.
To do so, provide a closure to the [Engine
] via Engine::on_var
.
let mut engine = Engine::new();
// Register a variable resolver.
engine.on_var(|name, index, context| {
match name {
"MYSTIC_NUMBER" => Ok(Some(42_i64.into())),
// Override a variable - make it not found even if it exists!
"DO_NOT_USE" => Err(EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE).into()),
// Silently maps 'chameleon' into 'innocent'.
"chameleon" => context.scope().get_value("innocent").map(Some).ok_or_else(||
EvalAltResult::ErrorVariableNotFound(name.to_string(), Position::NONE).into()
),
// Return Ok(None) to continue with the normal variable resolution process.
_ => Ok(None)
}
});
1. Avoid having to maintain a custom [`Scope`] with all [variables] regardless of need
(because a script may not use them all).
2. _Short-circuit_ [variable] access, essentially overriding standard behavior.
3. _Lazy-load_ [variables] when they are accessed, not up-front.
This benefits when the number of [variables] is very large, when they are timing-dependent,
or when they are expensive to load.
4. Rename system [variables] on a script-by-script basis without having to construct different [`Scope`]'s.
[Variable] values returned by a variable resolver are treated as _[constants]_.
This is to avoid needing a mutable reference to the underlying data provider which may not be possible to obtain.
To change these [variables], better push them into a custom [`Scope`] instead of
using a variable resolver.
It is possible to return a _shared_ value from a variable resolver.
This is one way to implement [Mutable Global State]({{rootUrl}}/patterns/global-mutable-state.md).
Function Signature
The function signature passed to Engine::on_var
takes the following form.
Fn(name: &str, index: usize, context: EvalContext) -> Result<Option<Dynamic>, Box<EvalAltResult>>
where:
Parameter | Type | Description |
---|---|---|
name |
&str |
[variable] name |
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 .If index is zero, then there is no pre-calculated offset position and a search through the current [Scope ] must be performed. |
context |
[EvalContext ] |
mutable reference to the current evaluation context |
and [EvalContext
] is a type that encapsulates the current evaluation context.
Return value
The return value is Result<Option<Dynamic>, Box<EvalAltResult>>
where:
Value | Description |
---|---|
Ok(None) |
normal [variable] resolution process should continue, i.e. continue searching through the [Scope ] |
Ok(Some(value)) |
value (a [Dynamic ]) of the [variable], treated as a [constant] |
Err(Box<EvalAltResult>) |
error that is reflected back to the [Engine ], normally EvalAltResult::ErrorVariableNotFound to indicate that the [variable] does not exist, but it can be any EvalAltResult . |