Make a Module Available to Scripts
Use Case 1 – Make It Globally Available
Engine::register_global_module
registers a shared module into the
global namespace.
This is by far the easiest way to expose a module’s functionalities to Rhai.
All functions, variables/constants and type iterators can be accessed without namespace qualifiers.
Sub-modules are ignored.
use rhai::{Engine, Module, FuncRegistration};
let mut module = Module::new(); // new module
// Add new function.
FuncRegistration::new("inc")
.with_params_info(&["x: i64", "i64"])
.set_into_module(&mut module, |x: i64| x + 1);
// Use 'Module::set_var' to add variables.
module.set_var("MYSTIC_NUMBER", 41_i64);
// Register the module into the global namespace of the Engine.
let mut engine = Engine::new();
engine.register_global_module(module.into());
// No need to import module...
engine.eval::<i64>("inc(MYSTIC_NUMBER)")? == 42;
Equivalent to Engine::register_XXX
Engine::register_fn
etc. are actually implemented by adding functions to an
internal module!
Registering a module via Engine::register_global_module
is essentially the same
as calling Engine::register_fn
(or any of the Engine::register_XXX
API) individually
on each top-level function within that module.
// The above is essentially the same as:
let mut engine = Engine::new();
engine.register_fn("inc", |x: i64| x + 1);
engine.eval::<i64>("inc(41)")? == 42; // no need to import module
Use Case 2 – Make It a Static Namespace
Engine::register_static_module
registers a module and under a specific
module namespace.
use rhai::{Engine, Module, FuncRegistration};
let mut module = Module::new(); // new module
// Add new function.
FuncRegistration::new("inc")
.with_params_info(&["x: i64", "i64"])
.set_into_module(&mut module, |x: i64| x + 1);
// Use 'Module::set_var' to add variables.
module.set_var("MYSTIC_NUMBER", 41_i64);
// Register the module into the Engine as the static module namespace path
// 'services::calc'
let mut engine = Engine::new();
engine.register_static_module("services::calc", module.into());
// Refer to the 'services::calc' module...
engine.eval::<i64>("services::calc::inc(services::calc::MYSTIC_NUMBER)")? == 42;
Expose functions to the global namespace
Type iterators are special — they are always exposed to the global namespace.
The Module
API can optionally expose functions to the global namespace
by setting the namespace
parameter to FnNamespace::Global
.
This way, getters/setters and indexers for custom types can work as expected.
use rhai::{Engine, Module, FuncRegistration, FnNamespace};
let mut module = Module::new(); // new module
// Add new function.
FuncRegistration::new("inc")
.with_params_info(&["x: i64", "i64"])
.with_namespace(FnNamespace::Global) // <- global namespace
.set_into_module(&mut module, |x: i64| x + 1);
// Use 'Module::set_var' to add variables.
module.set_var("MYSTIC_NUMBER", 41_i64);
// Register the module into the Engine as a static module namespace 'calc'
let mut engine = Engine::new();
engine.register_static_module("calc", module.into());
// 'inc' works when qualified by the namespace
engine.eval::<i64>("calc::inc(calc::MYSTIC_NUMBER)")? == 42;
// 'inc' also works without a namespace qualifier
// because it is exposed to the global namespace
engine.eval::<i64>("let x = calc::MYSTIC_NUMBER; x.inc()")? == 42;
engine.eval::<i64>("let x = calc::MYSTIC_NUMBER; inc(x)")? == 42;
Use Case 3 – Make It Dynamically Loadable
In order to dynamically load a custom module, there must be a module resolver which serves
the module when loaded via import
statements.
The easiest way is to use, for example, the StaticModuleResolver
to hold such
a custom module.
use rhai::{Engine, Scope, Module, FuncRegistration};
use rhai::module_resolvers::StaticModuleResolver;
let mut module = Module::new(); // new module
module.set_var("answer", 41_i64); // variable 'answer' under module
FuncRegistration::new("inc")
.with_params_info(&["x: i64"])
.set_into_module(&mut module, |x: i64| x + 1);
// Create the module resolver
let mut resolver = StaticModuleResolver::new();
// Add the module into the module resolver under the name 'question'
// They module can then be accessed via: 'import "question" as q;'
resolver.insert("question", module);
// Set the module resolver into the 'Engine'
let mut engine = Engine::new();
engine.set_module_resolver(resolver);
// Use namespace-qualified variables
engine.eval::<i64>(
r#"
import "question" as q;
q::answer + 1
"#)? == 42;
// Call namespace-qualified functions
engine.eval::<i64>(
r#"
import "question" as q;
q::inc(q::answer)
"#)? == 42;