257 lines
8.4 KiB
Markdown
257 lines
8.4 KiB
Markdown
Create a Custom Package
|
|
=======================
|
|
|
|
{{#include ../../links.md}}
|
|
|
|
```admonish info.side "See also"
|
|
|
|
See also the [_One Engine Instance Per Call_]({{rootUrl}}/patterns/parallel.md) pattern.
|
|
```
|
|
|
|
The macro `def_package!` can be used to create a custom [package].
|
|
|
|
A custom [package] can aggregate many other [packages] into a single self-contained unit.
|
|
More functions can be added on top of others.
|
|
|
|
Custom [packages] are extremely useful when multiple [raw `Engine`] instances must be created such
|
|
that they all share the same set of functions.
|
|
|
|
|
|
`def_package!`
|
|
--------------
|
|
|
|
> ```rust
|
|
> def_package! {
|
|
> /// Package description doc-comment
|
|
> pub name(variable) {
|
|
> :
|
|
> // package init code block
|
|
> :
|
|
> }
|
|
>
|
|
> // Multiple packages can be defined at the same time,
|
|
> // possibly with base packages and/or code to setup an Engine.
|
|
>
|
|
> /// Package description doc-comment
|
|
> pub(crate) name(variable) : base_package_1, base_package_2, ... {
|
|
> :
|
|
> // package init code block
|
|
> :
|
|
> } |> |engine| {
|
|
> :
|
|
> // engine setup code block
|
|
> :
|
|
> }
|
|
>
|
|
> /// A private package description doc-comment
|
|
> name(variable) {
|
|
> :
|
|
> // private package init code block
|
|
> :
|
|
> }
|
|
>
|
|
> :
|
|
> }
|
|
> ```
|
|
|
|
where:
|
|
|
|
| Element | Description |
|
|
| :---------------------: | ---------------------------------------------------------------------------------------------------- |
|
|
| description | doc-comment for the [package] |
|
|
| `pub` etc. | visibility of the [package] |
|
|
| name | name of the [package], usually ending in ...`Package` |
|
|
| variable | a variable name holding a reference to the [module] forming the [package], usually `module` or `lib` |
|
|
| base_package | an external [package] type that is merged into this [package] as a dependency |
|
|
| package init code block | a code block that initializes the [package] |
|
|
| engine | a variable name holding a mutable reference to an [`Engine`] |
|
|
| engine setup code block | a code block that performs setup tasks on an [`Engine`] during registration |
|
|
|
|
|
|
Examples
|
|
--------
|
|
|
|
```rust
|
|
// Import necessary types and traits.
|
|
use rhai::def_package; // 'def_package!' macro
|
|
use rhai::packages::{ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage};
|
|
use rhai::{FuncRegistration, CustomType, TypeBuilder};
|
|
|
|
/// This is a custom type.
|
|
#[derive(Clone, CustomType)]
|
|
struct TestStruct {
|
|
foo: String,
|
|
bar: i64,
|
|
baz: bool
|
|
}
|
|
|
|
def_package! {
|
|
/// My own personal super package
|
|
// Aggregate other base packages (if any) simply by listing them after a colon.
|
|
pub MyPackage(module) : ArithmeticPackage, LogicPackage, BasicArrayPackage, BasicMapPackage
|
|
{
|
|
// Register additional Rust function.
|
|
FuncRegistration::new("get_bar_value")
|
|
.with_params_info(&["s: &mut TestStruct", "i64"])
|
|
.set_into_module(module, |s: &mut TestStruct| s.bar);
|
|
|
|
// Register a function for use as a custom operator.
|
|
FuncRegistration::new("@")
|
|
.with_namespace(FnNamespace::Global) // <- make it available globally.
|
|
.set_into_module(module, |x: i64, y: i64| x * x + y * y);
|
|
} |> |engine| {
|
|
// This optional block performs tasks on an 'Engine' instance,
|
|
// e.g. register custom types and/or custom operators/syntax.
|
|
|
|
// Register custom type.
|
|
engine.build_type::<TestStruct>();
|
|
|
|
// Define a custom operator '@' with precedence of 160
|
|
// (i.e. between +|- and *|/).
|
|
engine.register_custom_operator("@", 160).unwrap();
|
|
}
|
|
}
|
|
```
|
|
|
|
~~~admonish tip.small "Tip: Feature gates on base packages"
|
|
|
|
Base packages in the list after the colon (`:`) can also have attributes (such as feature gates)!
|
|
|
|
```rust
|
|
def_package! {
|
|
// 'BasicArrayPackage' is used only under 'arrays' feature.
|
|
pub MyPackage(module) :
|
|
ArithmeticPackage,
|
|
LogicPackage,
|
|
#[cfg(feature = "arrays")]
|
|
BasicArrayPackage
|
|
{
|
|
...
|
|
}
|
|
}
|
|
|
|
```
|
|
~~~
|
|
|
|
~~~admonish danger.small "Advanced: `Engine` setup with `|>`"
|
|
|
|
A second code block (in the syntax of a [closure]) following a right-triangle symbol (`|>`)
|
|
is run whenever the [package] is being registered.
|
|
|
|
It allows performing setup tasks directly on that [`Engine`], e.g. registering [custom types],
|
|
[custom operators] and/or [custom syntax].
|
|
|
|
```rust
|
|
def_package! {
|
|
pub MyPackage(module) {
|
|
:
|
|
:
|
|
} |> |engine| {
|
|
// Call methods on 'engine'
|
|
}
|
|
}
|
|
```
|
|
~~~
|
|
|
|
|
|
Create a Custom Package from a Plugin Module
|
|
--------------------------------------------
|
|
|
|
```admonish question.side "Trivia"
|
|
|
|
This is exactly how Rhai's built-in [packages], such as `BasicMathPackage`, are actually implemented.
|
|
```
|
|
|
|
By far the easiest way to create a custom [package] is to call `plugin::combine_with_exported_module!`
|
|
from within `def_package!` which simply merges in all the functions defined within a [plugin module].
|
|
|
|
Due to specific requirements of a [package], `plugin::combine_with_exported_module!`
|
|
_flattens_ all sub-modules (i.e. all functions and [type iterators] defined within sub-modules
|
|
are pulled up to the top level instead) and so there will not be any sub-modules added to the [package].
|
|
|
|
Variables in the [plugin module] are ignored.
|
|
|
|
```rust
|
|
// Import necessary types and traits.
|
|
use rhai::def_package;
|
|
use rhai::packages::{ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage};
|
|
use rhai::plugin::*;
|
|
|
|
// Define plugin module.
|
|
#[export_module]
|
|
mod my_plugin_module {
|
|
// Custom type.
|
|
pub type ABC = TestStruct;
|
|
|
|
// Public constant.
|
|
pub const MY_NUMBER: i64 = 42;
|
|
|
|
// Public function.
|
|
pub fn greet(name: &str) -> String {
|
|
format!("hello, {}!", name)
|
|
}
|
|
|
|
// Non-public functions are by default not exported.
|
|
fn get_private_num() -> i64 {
|
|
42
|
|
}
|
|
|
|
// Public function.
|
|
pub fn get_num() -> i64 {
|
|
get_private_num()
|
|
}
|
|
|
|
// Custom operator.
|
|
#[rhai_fn(name = "@")]
|
|
pub fn square_add(x: i64, y: i64) -> i64 {
|
|
x * x + y * y
|
|
}
|
|
|
|
// A sub-module. If using 'combine_with_exported_module!', however,
|
|
// it will be flattened and all functions registered at the top level.
|
|
//
|
|
// Because of this flattening, sub-modules are very convenient for
|
|
// putting feature gates onto large groups of functions.
|
|
#[cfg(feature = "sub-num-feature")]
|
|
pub mod my_sub_module {
|
|
// Only available under 'sub-num-feature'.
|
|
pub fn get_sub_num() -> i64 {
|
|
0
|
|
}
|
|
}
|
|
}
|
|
|
|
def_package! {
|
|
/// My own personal super package
|
|
// Aggregate other base packages (if any) simply by listing them after a colon.
|
|
pub MyPackage(module) : ArithmeticPackage, LogicPackage, BasicArrayPackage, BasicMapPackage
|
|
{
|
|
// Merge all registered functions and constants from the plugin module
|
|
// into the custom package.
|
|
//
|
|
// The sub-module 'my_sub_module' is flattened and its functions
|
|
// registered at the top level.
|
|
//
|
|
// The text string name in the second parameter can be anything
|
|
// and is reserved for future use; it is recommended to be an
|
|
// ID string that uniquely identifies the plugin module.
|
|
//
|
|
// The constant variable, 'MY_NUMBER', is ignored.
|
|
//
|
|
// This call ends up registering three functions at the top level of
|
|
// the package:
|
|
// 1) 'greet'
|
|
// 2) 'get_num'
|
|
// 3) 'get_sub_num' (flattened from 'my_sub_module')
|
|
//
|
|
combine_with_exported_module!(module, "my-mod", my_plugin_module));
|
|
} |> |engine| {
|
|
// This optional block is used to set up an 'Engine' during registration.
|
|
|
|
// Define a custom operator '@' with precedence of 160
|
|
// (i.e. between +|- and *|/).
|
|
engine.register_custom_operator("@", 160).unwrap();
|
|
}
|
|
}
|
|
```
|