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)
3. [Disable Custom Types](rust/disable-custom.md)
4. [Printing Custom Types](rust/print-custom.md)
9. [Packages](rust/packages/index.md)
1. [Built-in Packages](rust/packages/builtin.md)
2. [Custom Packages](rust/packages/create.md)
10. [Modules](rust/modules/index.md)
9. [Modules](rust/modules/index.md)
1. [Create from Rust](rust/modules/create.md)
2. [Create from AST](rust/modules/ast.md)
3. [Module Resolvers](rust/modules/resolvers.md)
1. [Custom Implementation](rust/modules/imp-resolver.md)
11. [Plugins](plugins/index.md)
1. [Custom Module Resolvers](rust/modules/imp-resolver.md)
10. [Plugins](plugins/index.md)
1. [Export a Rust Module](plugins/module.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)
1. [Comments](language/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)
8. [Scriptable Event Handler with State](patterns/events.md)
9. [Dynamic Constants Provider](patterns/dynamic-const.md)
9. [Advanced Topics](advanced.md)
1. [Capture Scope for Function Call](language/fn-capture.md)
2. [Low-Level API](rust/register-raw.md)
3. [Variable Resolver](engine/var.md)
4. [Use as DSL](engine/dsl.md)
9. [Advanced Topics](advanced.md)
10. [Capture Scope for Function Call](language/fn-capture.md)
11. [Low-Level API](rust/register-raw.md)
12. [Variable Resolver](engine/var.md)
13. [Use as DSL](engine/dsl.md)
1. [Disable Keywords and/or Operators](engine/disable.md)
2. [Custom Operators](engine/custom-op.md)
3. [Extending with Custom Syntax](engine/custom-syntax.md)
5. [Multiple Instantiation](patterns/multiple.md)
6. [Functions Metadata](engine/metadata/index.md)
1. [Generate Function Signatures](engine/metadata/gen_fn_sig.md)
2. [Export Metadata to JSON](engine/metadata/export_to_json.md)
14. [Multiple Instantiation](patterns/multiple.md)
15. [Functions Metadata](engine/metadata/index.md)
4. [Generate Function Signatures](engine/metadata/gen_fn_sig.md)
5. [Export Metadata to JSON](engine/metadata/export_to_json.md)
10. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.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:
| Namespace | How Many | Source | Lookup method | 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 |
| Module | Many | [`Module`] | namespace-qualified function name | yes | yes |
| Namespace | How Many | Source | Lookup | Sub-modules? | Variables? |
| --------- | :------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | :----------: | :--------: |
| 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 | 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.
_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.
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
`Engine::register_global_module`.
* Functions defined in [modules] loaded via `Engine::register_static_module` that are specifically marked
for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]).
* Functions defined in [modules] registered via `Engine::register_static_module` that are specifically
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
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"
engine
.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:

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

View File

@ -101,7 +101,7 @@ fn main() {
let module = exported_module!(my_module);
// 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);
// 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.
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`].