Revise package terminology.

This commit is contained in:
Stephen Chung
2020-12-23 19:11:41 +08:00
parent 08e7ad8c09
commit 7d58324ad4
10 changed files with 129 additions and 95 deletions

View File

@@ -19,8 +19,8 @@ Manually creating a [module] is possible via the `Module` API.
For the complete `Module` API, refer to the [documentation](https://docs.rs/rhai/{{version}}/rhai/struct.Module.html) online.
Make the `Module` Globally Available
-----------------------------------
Use Case 1 - Make the `Module` Globally Available
------------------------------------------------
`Engine::register_global_module` registers a shared [module] into the _global_ namespace.
@@ -44,14 +44,14 @@ 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);
engine.register_global_module(module.into());
engine.eval::<i64>("inc(41)")? == 42; // no need to import module
```
Make the `Module` a Static Module
--------------------------------
Use Case 2 - Make the `Module` a Static Module
---------------------------------------------
`Engine::register_static_module` registers a [module] and under a specific module namespace.
@@ -69,15 +69,18 @@ module.update_fn_metadata(hash, ["x: 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);
engine.register_static_module("calc", module.into());
engine.eval::<i64>("calc::inc(41)")? == 42; // refer to the 'Calc' module
```
`Module::set_fn_XXX_mut` can expose functions (usually _methods_) in the module
to the _global_ namespace, so [getters/setters] and [indexers] for [custom types] can work as expected.
### Expose Functions to the Global Namespace
[Type iterators], because of their special nature, are always exposed to the _global_ namespace.
`Module::set_fn_mut` and `Module::set_fn_XXX_mut` can optionally expose functions (usually _methods_)
in the module to the _global_ namespace, 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.
```rust
use rhai::{Engine, Module, FnNamespace};
@@ -93,15 +96,15 @@ 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);
engine.register_static_module("calc", module.into());
// The method 'inc' works as expected because it is exposed to the global namespace
engine.eval::<i64>("let x = 41; x.inc()")? == 42;
```
Make the `Module` Dynamically Loadable
-------------------------------------
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.

View File

@@ -3,12 +3,27 @@ Modules
{{#include ../../links.md}}
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
Modules can be disabled via the [`no_module`] feature.
Rhai allows organizing functionalities (functions, both Rust-based or script-based, and variables)
into independent _modules_. Modules can be disabled via the [`no_module`] feature.
A module is of the type `Module` and holds a collection of functions, variables, [type iterators] and sub-modules.
It may be created entirely from Rust functions, or it may encapsulate a Rhai script together with the functions
and variables defined by that script.
A module is of the type `Module` and holds a collection of functions, variables,
[type iterators] and sub-modules.
It may be created entirely from Rust functions, or it may encapsulate a Rhai script together
with the functions and variables defined by that script.
Other scripts can then load this module and use the functions and variables exported
as if they were defined inside the same script.
Alternatively, modules can be registered directly into an [`Engine`] and made available
to scripts either globally or under individual static module [_namespaces_][function namespaces].
Usage Patterns
--------------
| Usage | API | Lookup | Sub-modules? | Variables? |
| -------------- | :-------------------------------: | :----------------------: | :----------: | :--------: |
| Global module | `Engine:: register_global_module` | simple name | ignored | ignored |
| Static module | `Engine:: register_static_module` | namespace-qualified name | yes | yes |
| Dynamic module | [`import`] statement | namespace-qualified name | yes | yes |

View File

@@ -23,10 +23,10 @@ Built-In Packages
| `StandardPackage` | standard library (default for `Engine::new`) | no | yes |
Load the `CorePackage`
---------------------
`CorePackage`
-------------
If only minimal functionalities is required, load the `CorePackage` instead:
If only minimal functionalities are required, register the `CorePackage` instead:
```rust
use rhai::Engine;
@@ -35,6 +35,6 @@ use rhai::packages::{Package, CorePackage};
let mut engine = Engine::new_raw();
let package = CorePackage::new();
// Register the package into the Engine by converting it into a shared module.
// Register the package into the 'Engine' by converting it into a shared module.
engine.register_global_module(package.as_shared_module());
```

View File

@@ -3,33 +3,31 @@ Create a Custom Package
{{#include ../../links.md}}
Sometimes specific functionalities are needed, so custom packages can be created.
A custom package is a convenient means to gather up a number of functions for later use.
An [`Engine`] only needs to `Engine::register_global_module` the custom package once to gain access
to the entire set of functions within.
The macro `def_package!` can be used to create a custom [package].
Registering a package into an [`Engine`] is functionally equivalent to calling `Engine::register_fn` etc.
on _each_ of the functions inside the package. But because packages are _shared_, using a package is
_much_ cheaper than registering all the functions one by one.
The macro `rhai::def_package!` can be used to create a new 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.
Macro Parameters
---------------
`def_package!`
--------------
`def_package!(root:package_name:description, variable, block)`
> `def_package!(root:package_name:description, variable, block)`
* `root` - root namespace, usually `"rhai"`.
where:
* `package_name` - name of the package, usually ending in `Package`.
| Parameter | Description |
| :------------: | ----------------------------------------------------------------------------------------------- |
| `root` | root namespace, usually `rhai` |
| `package_name` | name of the package, usually ending in `...Package` |
| `description` | doc-comment for the package |
| `variable` | a variable name holding a reference to the [module] (`&mut Module`) that is to form the package |
| `block` | a code block that initializes the package |
* `description` - doc comment for the package.
* `variable` - a variable name holding a reference to the [module] that is to form the package.
* `block` - a code block that initializes the package.
Examples
--------
```rust
// Import necessary types and traits.
@@ -43,7 +41,7 @@ use rhai::{
// Define the package 'MyPackage'.
def_package!(rhai:MyPackage:"My own personal super package", module, {
// Aggregate existing packages simply by calling 'init' on each.
// Aggregate other packages simply by calling 'init' on each.
ArithmeticPackage::init(module);
LogicPackage::init(module);
BasicArrayPackage::init(module);
@@ -64,14 +62,14 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
Create a Custom Package from a Plugin Module
-------------------------------------------
By far the easiest way to create a custom module is to call `rhai::plugin::combine_with_exported_module!`
from within `rhai::def_package!` which simply merges in all the functions defined within a [plugin module].
By far the easiest way to create a custom module is to call `plugin::combine_with_exported_module!`
from within `def_package!` which simply merges in all the functions defined within a [plugin module].
In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented.
Because of the specific requirements of a [package], all sub-modules are _flattened_
(i.e. all functions defined within sub-modules are pulled up and registered at the top level instead)
and so there will not be any sub-modules added to the package.
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.
@@ -107,7 +105,7 @@ mod my_module {
// Define the package 'MyPackage'.
def_package!(rhai:MyPackage:"My own personal super package", module, {
// Aggregate existing packages simply by calling 'init' on each.
// Aggregate other packages simply by calling 'init' on each.
ArithmeticPackage::init(module);
LogicPackage::init(module);
BasicArrayPackage::init(module);

View File

@@ -3,40 +3,56 @@ Packages
{{#include ../../links.md}}
Standard built-in Rhai features are provided in various _packages_ that can be registered into the
The built-in library of Rhai is provided as various _packages_ that can be
turned into _shared_ [modules], which in turn can be registered into the
_global namespace_ of an [`Engine`] via `Engine::register_global_module`.
Packages reside under `rhai::packages::*` and the trait `rhai::packages::Package` must be loaded in order for
packages to be used.
Packages reside under `rhai::packages::*` and the trait `rhai::packages::Package`
must be loaded in order for packages to be used.
### Packages _are_ Modules
Internally, a _package_ is a _newtype_ wrapping a pre-defined [module],
with some conveniences to make it easier to define and use as a standard
_library_ for an [`Engine`].
Packages typically contain Rust functions that are callable within a Rhai script.
All _top-level_ functions in a package are available under the _global namespace_
(i.e. they're available without namespace qualifiers).
Once a package is created (e.g. via `Package::new`), it can be _shared_ (via `Package::as_shared_module`)
among multiple instances of [`Engine`], even across threads (under [`sync`]).
Therefore, a package only has to be created _once_.
Sub-modules and variables are ignored in packages.
Share a Package Among Multiple `Engine`'s
----------------------------------------
`Engine::register_global_module` and `Engine::register_static_module` both require _shared_ [modules].
Once a package is created (e.g. via `Package::new`), it can create _shared_ [modules]
(via `Package::as_shared_module`) and register them into multiple instances of [`Engine`],
even across threads (under the [`sync`] feature).
Therefore, a package only has to be created _once_ and essentially shared among multiple
[`Engine`] instances. This is particular useful when spawning large number of [raw `Engine`'s][raw `Engine`].
```rust
use rhai::Engine;
use rhai::packages::Package // load the 'Package' trait to use packages
use rhai::packages::CorePackage; // the 'core' package contains basic functionalities (e.g. arithmetic)
// Create a 'raw' Engine
let mut engine = Engine::new_raw();
// Create a package - can be shared among multiple `Engine` instances
// Create a package - can be shared among multiple 'Engine' instances
let package = CorePackage::new();
// Register the package into the global namespace.
// 'Package::as_shared_module' converts the package into a shared module.
engine.register_global_module(package.as_shared_module());
let mut engines_collection: Vec<Engine> = Vec::new();
// Create 100 'raw' Engines
for _ in 0..100 {
let mut engine = Engine::new_raw();
// Register the package into the global namespace.
// 'Package::as_shared_module' converts the package into a shared module.
engine.register_global_module(package.as_shared_module());
engines_collection.push(engine);
}
```
Share a Package Among `Engine`s
------------------------------
`Engine::register_global_module` consumes the input shared module.
However, `Package::as_shared_module` can be called multiple times for multiple instances of [`Engine`].