Add writeup on plugins.
This commit is contained in:
78
doc/src/plugins/function.md
Normal file
78
doc/src/plugins/function.md
Normal file
@@ -0,0 +1,78 @@
|
||||
Create a Plugin Function
|
||||
========================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
Sometimes only a few ad hoc functions are required and it is simpler to register
|
||||
individual functions instead of a full-blown [plugin module].
|
||||
|
||||
|
||||
Macros
|
||||
------
|
||||
|
||||
| Macro | Apply to | Behavior |
|
||||
| ------------------------ | ------------------------------------------------------------- | --------------------------------------------------------- |
|
||||
| `#[export_fn]` | Rust function defined in module | Export the function |
|
||||
| `#[rhai_fn(return_raw)]` | Rust function returning `Result<Dynamic, Box<EvalAltResult>>` | Specify that this is a fallible function |
|
||||
| `register_exported_fn!` | [`Engine`] instance, register name, function name | Register function with the [`Engine`] under specific name |
|
||||
| `set_exported_fn!` | [`Module`], register name, function name | Register function with the [`Module`] under specific name |
|
||||
|
||||
|
||||
`#[export_fn]` and `register_exported_fn!`
|
||||
-----------------------------------------
|
||||
|
||||
Apply `#[export_fn]` onto a function defined at _module level_ to convert it into a Rhai plugin function.
|
||||
|
||||
The function cannot be nested inside another function - it can only be defined directly under a module.
|
||||
|
||||
To register the plugin function, simply call `register_exported_fn!`. The name of the function can be
|
||||
any text string, so it is possible to register _overloaded_ functions as well as operators.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_fn]
|
||||
fn increment(num: &mut i64) {
|
||||
*num += 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// 'register_exported_fn!' registers the function as 'inc' with the Engine.
|
||||
register_exported_fn!(engine, "inc", increment);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Fallible Functions
|
||||
------------------
|
||||
|
||||
To register [fallible functions] (i.e. functions that may return errors), apply the
|
||||
`#[rhai_fn(return_raw)]` attribute on plugin functions that return `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
|
||||
A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does not
|
||||
have the appropriate return type.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_fn]
|
||||
#[rhai_fn(return_raw)]
|
||||
pub fn double_and_divide(x: i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
if y == 0 {
|
||||
Err("Division by zero!".into())
|
||||
} else {
|
||||
let result = (x * 2) / y;
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// Overloads the operator '+' with the Engine.
|
||||
register_exported_fn!(engine, "+", double_and_divide);
|
||||
}
|
||||
```
|
11
doc/src/plugins/index.md
Normal file
11
doc/src/plugins/index.md
Normal file
@@ -0,0 +1,11 @@
|
||||
Plugins
|
||||
=======
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
Rhai contains a robust _plugin_ system that greatly simplifies registration of custom functions.
|
||||
|
||||
Instead of the large `Engine::register_XXX` API, and the parallel `Module::set_fn_XXX` API,
|
||||
a _plugin_ simplifies the work of creating and registering multiple functions into an [`Engine`].
|
||||
|
||||
Plugins are processed via a set of procedural macros under the `rhai::plugins` module.
|
194
doc/src/plugins/module.md
Normal file
194
doc/src/plugins/module.md
Normal file
@@ -0,0 +1,194 @@
|
||||
Create a Plugin Module
|
||||
======================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
The core of creating a plugin [module] is the `#[export_module]` attribute.
|
||||
|
||||
When applied on a module definition, `#[export_module]` automatically generates Rhai-acceptable
|
||||
functions from all `pub` functions defined within.
|
||||
|
||||
The resulting module can then be loaded into an [`Engine`] as a normal [module],
|
||||
or as a [custom package].
|
||||
|
||||
|
||||
Macros
|
||||
------
|
||||
|
||||
| Macro | Apply to | Behavior |
|
||||
| --------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------- |
|
||||
| `#[export_module]` | Rust module | Export all `pub` functions |
|
||||
| `#[rhai_fn(skip)]` | Function in Rust module | Do not export this function |
|
||||
| `#[rhai_fn(return_raw)]` | `pub` function in Rust module returning `Result<Dynamic, Box<EvalAltResult>>` | Specify that this is a fallible function |
|
||||
| `#[rhai_fn(name = "...")]` | `pub` function in Rust module | Register function under specific name |
|
||||
| `#[rhai_fn(get = "...")]` | `pub` function in Rust module (first parameter must be `&mut`) | Register a property getter under specific name |
|
||||
| `#[rhai_fn(set = "...")]` | `pub` function in Rust module (first parameter must be `&mut`) | Register a property setter under specific name |
|
||||
| `#[rhai_fn(index_get]` | `pub` function in Rust module (first parameter must be `&mut`) | Register a index getter |
|
||||
| `#[rhai_fn(index_set)]` | `pub` function in Rust module (first parameter must be `&mut`) | Register a index setter |
|
||||
| `#[rhai_mod(name = "...")]` | `pub` sub-module in Rust module | Export the sub-module under specific name |
|
||||
| `exported_module!` | Rust module name | Create a [module] containing exported functions |
|
||||
|
||||
|
||||
`#[export_module]` and `exported_module!`
|
||||
----------------------------------------
|
||||
|
||||
Apply `#[export_module]` onto a standard module to convert all `pub` functions
|
||||
into Rhai plugin functions.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This function will be registered as 'greet'.
|
||||
pub fn greet(name: &str) -> String {
|
||||
format!("hello, {}!", name)
|
||||
}
|
||||
// This function will be registered as 'get_num'.
|
||||
pub fn get_num() -> i64 {
|
||||
mystic_number()
|
||||
}
|
||||
// This function will be registered as 'increment'.
|
||||
pub fn increment(num: &mut i64) {
|
||||
*num += 1;
|
||||
}
|
||||
// This function is NOT registered.
|
||||
fn mystic_number() -> i64 {
|
||||
42
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut engine = Engine::new();
|
||||
|
||||
// 'exported_module!' creates the plugin module.
|
||||
let module = exported_module!(my_module);
|
||||
|
||||
// A module can simply be loaded as a custom package.
|
||||
engine.load_package(module);
|
||||
}
|
||||
```
|
||||
|
||||
The above automatically defines a plugin module named `my_module` which can be converted into
|
||||
a Rhai [module] via `exported_module!`. The functions contained within the module definition
|
||||
(i.e. `greet`, `get_num` and `increment`) are automatically registered into the [`Engine`] when
|
||||
`Engine::load_package` is called.
|
||||
|
||||
```rust
|
||||
let x = greet("world");
|
||||
x == "hello, world!";
|
||||
|
||||
let x = greet(get_num().to_string());
|
||||
x == "hello, 42!";
|
||||
|
||||
let x = get_num();
|
||||
x == 42;
|
||||
|
||||
increment(x);
|
||||
x == 43;
|
||||
```
|
||||
|
||||
|
||||
Getters, Setters and Indexers
|
||||
-----------------------------
|
||||
|
||||
Functions can be marked as [getters/setters] and [indexers] for [custom types] via the `#[rhai_fn]`
|
||||
attribute, which is applied on a function level.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This is a normal function 'greet'.
|
||||
pub fn greet(name: &str) -> String {
|
||||
format!("hello, {}!", name)
|
||||
}
|
||||
// This is a getter for 'MyType::prop'.
|
||||
#[rhai_fn(get = "prop")]
|
||||
pub fn get_prop(obj: &mut MyType) -> i64 {
|
||||
obj.prop
|
||||
}
|
||||
// This is a setter for 'MyType::prop'.
|
||||
#[rhai_fn(set = "prop")]
|
||||
pub fn set_prop(obj: &mut MyType, value: i64) {
|
||||
obj.prop = value;
|
||||
}
|
||||
// This is an index getter for 'MyType'.
|
||||
#[rhai_fn(index_get)]
|
||||
pub fn get_index(obj: &mut MyType, index: i64) -> bool {
|
||||
obj.list[index]
|
||||
}
|
||||
// This is an index setter for 'MyType'.
|
||||
#[rhai_fn(index_get)]
|
||||
pub fn get_index(obj: &mut MyType, index: i64, state: bool) {
|
||||
obj.list[index] = state;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Function Overloading and Operators
|
||||
---------------------------------
|
||||
|
||||
Operators and overloaded functions can be specified via `#[rhai_fn(name = "...")]` applied upon
|
||||
individual functions.
|
||||
|
||||
The text string given as the `name` parameter to `#[rhai_fn]` is used to register the function with
|
||||
the [`Engine`], disregarding the actual name of the function.
|
||||
|
||||
With `#[rhai_fn(name = "...")]`, multiple functions may be registered under the same name in Rhai.
|
||||
|
||||
Operators (which require function names that are not valid for Rust) can also be registered this way.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This is the '+' operator for 'MyType'.
|
||||
#[rhai_fn(name = "+")]
|
||||
pub fn add(obj: &mut MyType, value: i64) {
|
||||
obj.prop += value;
|
||||
}
|
||||
// This function is 'calc (i64)'.
|
||||
#[rhai_fn(name = "calc")]
|
||||
pub fn calc_with_default(num: i64) -> i64 {
|
||||
...
|
||||
}
|
||||
// This function is 'calc (i64, bool)'.
|
||||
#[rhai_fn(name = "calc")]
|
||||
pub fn calc_with_option(num: i64, option: bool) -> i64 {
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Fallible Functions
|
||||
------------------
|
||||
|
||||
To register [fallible functions] (i.e. functions that may return errors), apply the
|
||||
`#[rhai_fn(return_raw)]` attribute on functions that return `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
|
||||
A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does not
|
||||
have the appropriate return type.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // import macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This overloads the '/' operator for i64.
|
||||
#[rhai_fn(name = "/", return_raw)]
|
||||
pub fn double_and_divide(x: i64, y: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
if y == 0 {
|
||||
Err("Division by zero!".into())
|
||||
} else {
|
||||
let result = (x * 2) / y;
|
||||
Ok(result.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
Reference in New Issue
Block a user