Create a Module from Rust
Create via Plugin
By far the simplest way to create a module is via a plugin module which converts a normal Rust module into a Rhai module via procedural macros.
Create via Module
API
Manually creating a module is possible via the Module
API.
For the complete Module
API, refer to the documentation online.
Use Case 1 – Make the Module
Globally Available
Engine::register_global_module
registers a shared module into the global namespace.
All functions and type iterators can be accessed without namespace qualifiers. Variables and sub-modules are ignored.
This is by far the easiest way to expose a module’s functionalities to Rhai.
#![allow(unused)] fn main() { use rhai::{Engine, Module}; let mut module = Module::new(); // new module // Use the 'Module::set_fn_XXX' API to add functions. let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1)); // Remember to update the parameter names/types and return type metadata. // 'Module::set_fn_XXX' by default does not set function metadata. module.update_fn_metadata(hash, ["x: i64", "i64"]); // Register the module into the global namespace of the Engine. let mut engine = Engine::new(); engine.register_global_module(module.into()); engine.eval::<i64>("inc(41)")? == 42; // no need to import 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. In fact, the actual implementation of
Engine::register_fn
etc. simply adds the function to an internal module!
#![allow(unused)] fn main() { // 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 the Module
a Static Module
Engine::register_static_module
registers a module and under a specific module namespace.
#![allow(unused)] fn main() { use rhai::{Engine, Module}; let mut module = Module::new(); // new module // Use the 'Module::set_fn_XXX' API to add functions. let hash = module.set_fn_1("inc", |x: i64| Ok(x + 1)); // Remember to update the parameter names/types and return type metadata. // 'Module::set_fn_XXX' by default does not set function metadata. module.update_fn_metadata(hash, ["x: i64", "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(41)")? == 42; }
Expose Functions to the Global Namespace
The Module::set_fn_XXX_mut
API methods can optionally expose functions in the module
to the global namespace by setting the namespace
parameter to FnNamespace::Global
,
so getters/setters and indexers for custom types can work as expected.
Type iterators, because of their special nature, are always exposed to the global namespace.
#![allow(unused)] fn main() { use rhai::{Engine, Module, FnNamespace}; let mut module = Module::new(); // new module // Expose method 'inc' to the global namespace (default is 'FnNamespace::Internal') let hash = module.set_fn_1_mut("inc", FnNamespace::Global, |x: &mut i64| Ok(x + 1)); // Remember to update the parameter names/types and return type metadata. // 'Module::set_fn_XXX_mut' by default does not set function metadata. module.update_fn_metadata(hash, ["x: &mut i64", "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(41)")? == 42; // 'inc' also works without a namespace qualifier // because it is exposed to the global namespace engine.eval::<i64>("let x = 41; x.inc()")? == 42; engine.eval::<i64>("let x = 41; inc(x)")? == 42; }
Use Case 3 – Make the Module
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.
#![allow(unused)] fn main() { use rhai::{Engine, Scope, Module}; use rhai::module_resolvers::StaticModuleResolver; let mut module = Module::new(); // new module module.set_var("answer", 41_i64); // variable 'answer' under module module.set_fn_1("inc", |x: i64| Ok(x + 1)); // use the 'set_fn_XXX' API to add functions // 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; }