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

@ -41,17 +41,17 @@ The Rhai Scripting Language
2. [Indexers](rust/indexers.md) 2. [Indexers](rust/indexers.md)
3. [Disable Custom Types](rust/disable-custom.md) 3. [Disable Custom Types](rust/disable-custom.md)
4. [Printing Custom Types](rust/print-custom.md) 4. [Printing Custom Types](rust/print-custom.md)
9. [Packages](rust/packages/index.md) 9. [Modules](rust/modules/index.md)
1. [Built-in Packages](rust/packages/builtin.md)
2. [Custom Packages](rust/packages/create.md)
10. [Modules](rust/modules/index.md)
1. [Create from Rust](rust/modules/create.md) 1. [Create from Rust](rust/modules/create.md)
2. [Create from AST](rust/modules/ast.md) 2. [Create from AST](rust/modules/ast.md)
3. [Module Resolvers](rust/modules/resolvers.md) 3. [Module Resolvers](rust/modules/resolvers.md)
1. [Custom Implementation](rust/modules/imp-resolver.md) 1. [Custom Module Resolvers](rust/modules/imp-resolver.md)
11. [Plugins](plugins/index.md) 10. [Plugins](plugins/index.md)
1. [Export a Rust Module](plugins/module.md) 1. [Export a Rust Module](plugins/module.md)
2. [Export a Rust Function](plugins/function.md) 2. [Export a Rust Function](plugins/function.md)
11. [Packages](rust/packages/index.md)
1. [Built-in Packages](rust/packages/builtin.md)
2. [Custom Packages](rust/packages/create.md)
5. [Rhai Language Reference](language/index.md) 5. [Rhai Language Reference](language/index.md)
1. [Comments](language/comments.md) 1. [Comments](language/comments.md)
1. [Doc-Comments](language/doc-comments.md) 1. [Doc-Comments](language/doc-comments.md)
@ -127,18 +127,18 @@ The Rhai Scripting Language
7. [One Engine Instance Per Call](patterns/parallel.md) 7. [One Engine Instance Per Call](patterns/parallel.md)
8. [Scriptable Event Handler with State](patterns/events.md) 8. [Scriptable Event Handler with State](patterns/events.md)
9. [Dynamic Constants Provider](patterns/dynamic-const.md) 9. [Dynamic Constants Provider](patterns/dynamic-const.md)
9. [Advanced Topics](advanced.md) 9. [Advanced Topics](advanced.md)
1. [Capture Scope for Function Call](language/fn-capture.md) 10. [Capture Scope for Function Call](language/fn-capture.md)
2. [Low-Level API](rust/register-raw.md) 11. [Low-Level API](rust/register-raw.md)
3. [Variable Resolver](engine/var.md) 12. [Variable Resolver](engine/var.md)
4. [Use as DSL](engine/dsl.md) 13. [Use as DSL](engine/dsl.md)
1. [Disable Keywords and/or Operators](engine/disable.md) 1. [Disable Keywords and/or Operators](engine/disable.md)
2. [Custom Operators](engine/custom-op.md) 2. [Custom Operators](engine/custom-op.md)
3. [Extending with Custom Syntax](engine/custom-syntax.md) 3. [Extending with Custom Syntax](engine/custom-syntax.md)
5. [Multiple Instantiation](patterns/multiple.md) 14. [Multiple Instantiation](patterns/multiple.md)
6. [Functions Metadata](engine/metadata/index.md) 15. [Functions Metadata](engine/metadata/index.md)
1. [Generate Function Signatures](engine/metadata/gen_fn_sig.md) 4. [Generate Function Signatures](engine/metadata/gen_fn_sig.md)
2. [Export Metadata to JSON](engine/metadata/export_to_json.md) 5. [Export Metadata to JSON](engine/metadata/export_to_json.md)
10. [Appendix](appendix/index.md) 10. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.md) 1. [Keywords](appendix/keywords.md)
2. [Operators and Symbols](appendix/operators.md) 2. [Operators and Symbols](appendix/operators.md)

View File

@ -15,18 +15,20 @@ allow combining all functions in one [`AST`] into another, forming a new, unifie
In general, there are two types of _namespaces_ where functions are looked up: In general, there are two types of _namespaces_ where functions are looked up:
| Namespace | How Many | Source | Lookup method | Sub-modules? | Variables? | | Namespace | How Many | Source | Lookup | Sub-modules? | Variables? |
| --------- | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | :----------: | :--------: | | --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | :----------: | :--------: |
| Global | One | 1) [`AST`] being evaluated<br/>2) `Engine::register_XXX` API<br/>3) global [modules] loaded via `Engine::register_global_module`<br/>4) functions in static [modules] loaded via `Engine::register_static_module` and marked _global_ | simple function name | ignored | ignored | | Global | One | 1) [`AST`] being evaluated<br/>2) `Engine::register_XXX` API<br/>3) global [modules] registered via `Engine::register_global_module`<br/>4) functions in static [modules] registered via `Engine::register_static_module` and marked _global_ | simple name | ignored | ignored |
| Module | Many | [`Module`] | namespace-qualified function name | yes | yes | | Module | Many | 1) [Module] registered via `Engine::register_static_module`<br/>2) [Module] loaded via [`import`] statement | namespace-qualified name | yes | yes |
Module Namespace Module Namespaces
---------------- -----------------
There can be multiple module namespaces at any time during a script evaluation, loaded via the There can be multiple module namespaces at any time during a script evaluation, usually loaded via the
[`import`] statement. [`import`] statement.
_Static_ module namespaces can also be registered into an [`Engine`] via `Engine::register_static_module`.
Functions and variables in module namespaces are isolated and encapsulated within their own environments. Functions and variables in module namespaces are isolated and encapsulated within their own environments.
They must be called or accessed in a _namespace-qualified_ manner. They must be called or accessed in a _namespace-qualified_ manner.
@ -55,8 +57,8 @@ There is one _global_ namespace for every [`Engine`], which includes (in the fol
* All functions and iterators defined in global [modules] that are registered into the [`Engine`] via * All functions and iterators defined in global [modules] that are registered into the [`Engine`] via
`Engine::register_global_module`. `Engine::register_global_module`.
* Functions defined in [modules] loaded via `Engine::register_static_module` that are specifically marked * Functions defined in [modules] registered via `Engine::register_static_module` that are specifically
for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]). marked for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]).
Anywhere in a Rhai script, when a function call is made, the function is searched within the Anywhere in a Rhai script, when a function call is made, the function is searched within the
global namespace, in the above search order. global namespace, in the above search order.

View File

@ -116,7 +116,7 @@ let mut engine = Engine::new();
// Load the module as the module namespace "MyEnum" // Load the module as the module namespace "MyEnum"
engine engine
.register_type_with_name::<MyEnum>("MyEnum") .register_type_with_name::<MyEnum>("MyEnum")
.register_static_module("MyEnum", exported_module!(MyEnumModule)); .register_static_module("MyEnum", exported_module!(MyEnumModule).into());
``` ```
With this API in place, working with enums feels almost the same as in Rust: With this API in place, working with enums feels almost the same as in Rust:

View File

@ -146,7 +146,7 @@ pub mod bunny_api {
} }
} }
engine.register_global_module(exported_module!(bunny_api)); engine.register_global_module(exported_module!(bunny_api).into());
``` ```
### Push Constant Command Object into Custom Scope ### Push Constant Command Object into Custom Scope

View File

@ -101,7 +101,7 @@ fn main() {
let module = exported_module!(my_module); let module = exported_module!(my_module);
// A module can simply be registered into the global namespace. // A module can simply be registered into the global namespace.
engine.register_global_module(module); engine.register_global_module(module.into());
} }
``` ```
@ -140,7 +140,7 @@ fn main() {
let module = exported_module!(my_module); let module = exported_module!(my_module);
// A module can simply be registered as a static module namespace. // A module can simply be registered as a static module namespace.
engine.register_static_module("service", module); engine.register_static_module("service", module.into());
} }
``` ```

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. 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. `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. // Register the module into the global namespace of the Engine.
let mut engine = Engine::new(); 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 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. `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' // Register the module into the Engine as a static module namespace 'calc'
let mut engine = Engine::new(); 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 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 ### Expose Functions to the Global Namespace
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. `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 ```rust
use rhai::{Engine, Module, FnNamespace}; 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' // Register the module into the Engine as a static module namespace 'calc'
let mut engine = Engine::new(); 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 // The method 'inc' works as expected because it is exposed to the global namespace
engine.eval::<i64>("let x = 41; x.inc()")? == 42; 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 In order to dynamically load a custom module, there must be a [module resolver] which serves
the module when loaded via `import` statements. the module when loaded via `import` statements.

View File

@ -3,12 +3,27 @@ Modules
{{#include ../../links.md}} {{#include ../../links.md}}
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_. Rhai allows organizing functionalities (functions, both Rust-based or script-based, and variables)
Modules can be disabled via the [`no_module`] feature. 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. A module is of the type `Module` and holds a collection of functions, variables,
It may be created entirely from Rust functions, or it may encapsulate a Rhai script together with the functions [type iterators] and sub-modules.
and variables defined by that script.
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 Other scripts can then load this module and use the functions and variables exported
as if they were defined inside the same script. 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 | | `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 ```rust
use rhai::Engine; use rhai::Engine;
@ -35,6 +35,6 @@ use rhai::packages::{Package, CorePackage};
let mut engine = Engine::new_raw(); let mut engine = Engine::new_raw();
let package = CorePackage::new(); 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()); engine.register_global_module(package.as_shared_module());
``` ```

View File

@ -3,33 +3,31 @@ Create a Custom Package
{{#include ../../links.md}} {{#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. The macro `def_package!` can be used to create a custom [package].
An [`Engine`] only needs to `Engine::register_global_module` the custom package once to gain access
to the entire set of functions within.
Registering a package into an [`Engine`] is functionally equivalent to calling `Engine::register_fn` etc. A custom package can aggregate many other packages into a single self-contained unit.
on _each_ of the functions inside the package. But because packages are _shared_, using a package is More functions can be added on top of others.
_much_ cheaper than registering all the functions one by one.
The macro `rhai::def_package!` can be used to create a new custom package.
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. Examples
--------
* `block` - a code block that initializes the package.
```rust ```rust
// Import necessary types and traits. // Import necessary types and traits.
@ -43,7 +41,7 @@ use rhai::{
// Define the package 'MyPackage'. // Define the package 'MyPackage'.
def_package!(rhai:MyPackage:"My own personal super package", module, { 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); ArithmeticPackage::init(module);
LogicPackage::init(module); LogicPackage::init(module);
BasicArrayPackage::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 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!` By far the easiest way to create a custom module is to call `plugin::combine_with_exported_module!`
from within `rhai::def_package!` which simply merges in all the functions defined within a [plugin 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. 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_ Due to specific requirements of a [package], `plugin::combine_with_exported_module!`
(i.e. all functions defined within sub-modules are pulled up and registered at the top level instead) _flattens_ all sub-modules (i.e. all functions and [type iterators] defined within sub-modules
and so there will not be any sub-modules added to the package. 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. Variables in the [plugin module] are ignored.
@ -107,7 +105,7 @@ mod my_module {
// Define the package 'MyPackage'. // Define the package 'MyPackage'.
def_package!(rhai:MyPackage:"My own personal super package", module, { 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); ArithmeticPackage::init(module);
LogicPackage::init(module); LogicPackage::init(module);
BasicArrayPackage::init(module); BasicArrayPackage::init(module);

View File

@ -3,40 +3,56 @@ Packages
{{#include ../../links.md}} {{#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`. _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 reside under `rhai::packages::*` and the trait `rhai::packages::Package`
packages to be used. 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. 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_ All _top-level_ functions in a package are available under the _global namespace_
(i.e. they're available without namespace qualifiers). (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`) Sub-modules and variables are ignored in packages.
among multiple instances of [`Engine`], even across threads (under [`sync`]).
Therefore, a package only has to be created _once_.
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 ```rust
use rhai::Engine; use rhai::Engine;
use rhai::packages::Package // load the 'Package' trait to use packages use rhai::packages::Package // load the 'Package' trait to use packages
use rhai::packages::CorePackage; // the 'core' package contains basic functionalities (e.g. arithmetic) use rhai::packages::CorePackage; // the 'core' package contains basic functionalities (e.g. arithmetic)
// Create a 'raw' Engine // Create a package - can be shared among multiple 'Engine' instances
let mut engine = Engine::new_raw();
// Create a package - can be shared among multiple `Engine` instances
let package = CorePackage::new(); let package = CorePackage::new();
// Register the package into the global namespace. let mut engines_collection: Vec<Engine> = Vec::new();
// 'Package::as_shared_module' converts the package into a shared module.
engine.register_global_module(package.as_shared_module()); // 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`].