Revise docs for 0.19.0.

This commit is contained in:
Stephen Chung 2020-09-30 23:02:01 +08:00
parent a04ed02b54
commit cbc3d8764a
30 changed files with 291 additions and 125 deletions

View File

@ -14,8 +14,8 @@ Easy
* Easily [call a script-defined function]({{rootUrl}}/engine/call-fn.md) from Rust.
* Very few additional dependencies (right now only [`smallvec`](https://crates.io/crates/smallvec/));
for [`no-std`] builds, a number of additional dependencies are pulled in to provide for functionalities that used to be in `std`.
* Very few additional dependencies - right now only [`smallvec`](https://crates.io/crates/smallvec/) plus crates for procedural macros;
for [`no-std`] and `WASM` builds, a number of additional dependencies are pulled in to provide for missing functionalities.
Fast
----

View File

@ -3,6 +3,8 @@ What is Rhai
{{#include ../links.md}}
![Rhai Logo](../images/rhai_logo.png)
Rhai is an embedded scripting language and evaluation engine for Rust that gives a safe and easy way
to add scripting to any application.
@ -13,3 +15,27 @@ Versions
This Book is for version **{{version}}** of Rhai.
For the latest development version, see [here]({{rootUrl}}/vnext/).
Etymology of the name "Rhai"
---------------------------
### As per Rhai's author Johnathan Turner
In the beginning there was [ChaiScript](http://chaiscript.com),
which is an embedded scripting language for C++.
Originally it was intended to be a scripting language similar to **JavaScript**.
With java being a kind of hot beverage, the new language was named after
another hot beverage - **Chai**, which is the word for "tea" in many world languages
and, in particular, a popular kind of milk tea consumed in India.
Later, when the novel implementation technique behind ChaiScript was ported from C++ to Rust,
logically the `C` was changed to an `R` to make it "RhaiScript", or just "Rhai".
### On the origin of the temporary Rhai logo
One of Rhai's maintainers, Stephen Chung, was thinking about a logo when he accidentally
came across a copy of _Catcher in the Rye_ in a restaurant. The rest was history.
It is temporary until it becomes official, that is...

View File

@ -3,13 +3,11 @@ Licensing
{{#include ../links.md}}
Rhai is licensed under either:
Rhai is licensed under either of the following, at your choice:
* [Apache License, Version 2.0]({{repoHome}}/LICENSE-APACHE.txt), or
* [MIT license]({{repoHome}}/LICENSE-MIT.txt)
at your choice.
* [MIT license]({{repoHome}}/LICENSE-MIT.txt).
Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in this crate,
as defined in the Apache-2.0 license, shall be dual-licensed as above,

View File

@ -14,7 +14,7 @@ It doesn't attempt to be a new language. For example:
There is, however, a built-in [object map] type which is adequate for most uses.
It is possible to simulate [object-oriented programming (OOP)][OOP] by storing [function pointers]
in [object map] properties, turning them into _methods_.
or [closures] in [object map] properties, turning them into _methods_.
* No first-class functions - Code your functions in Rust instead, and register them with Rhai.
@ -22,22 +22,32 @@ It doesn't attempt to be a new language. For example:
* No garbage collection - this should be expected, so...
* No closures - do your closure magic in Rust instead; [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
* No first-class closures - do your closure magic in Rust instead: [turn a Rhai scripted function into a Rust closure]({{rootUrl}}/engine/call-fn.md).
But you can [curry][currying] a [function pointer] with arguments to simulate it somewhat.
There is, however, support for simulated [closures] via [currying] a [function pointer] with
captured shared variables.
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races. The purpose of Rhai is not
to be extremely _fast_, but to make it as easy as possible to integrate with native Rust applications.
* No byte-codes/JIT - Rhai has an AST-walking interpreter which will not win any speed races.
The purpose of Rhai is not to be extremely _fast_, but to make it as easy as possible to
integrate with native Rust applications.
* No formal language grammar - Rhai uses a hand-coded lexer, a hand-coded top-down recursive-descent parser
for statements and a Pratt parser for expressions.
This lack of formalism allows the parser itself to be exposed as a service in order to support
[disabling keywords/operators][disable keywords and operators], adding [custom operators],
and defining [custom syntax].
Do Not Write The Next 4D VR Game in Rhai
---------------------------------------
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting advanced language features
such as classes, inheritance, first-class functions, closures, concurrency, byte-codes, JIT etc.
Due to this intended usage, Rhai deliberately keeps the language simple and small by omitting
advanced language features such as classes, inheritance, first-class functions, closures,
concurrency, byte-codes VM, JIT etc.
Avoid the temptation to write full-fledge application logic entirely in Rhai - that use case is best fulfilled by
more complete languages such as JavaScript or Lua.
Avoid the temptation to write full-fledge application logic entirely in Rhai -
that use case is best fulfilled by more complete languages such as JavaScript or Lua.
Thin Dynamic Wrapper Layer Over Rust Code
@ -47,7 +57,8 @@ In actual practice, it is usually best to expose a Rust API into Rhai for script
All the core functionalities should be written in Rust, with Rhai being the dynamic _control_ layer.
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++ standard library.
This is similar to some dynamic languages where most of the core functionalities reside in a C/C++
standard library.
Another similar scenario is a web front-end driving back-end services written in a systems language.
In this case, JavaScript takes the role of Rhai while the back-end language, well... it can actually also be Rust.

View File

@ -5,7 +5,7 @@ Related Resources
Other online documentation resources for Rhai:
* [`crates.io`](https://crates.io/crates/rhai/) - Rhai crate
* [`crates.io`](https://crates.io/crates/rhai) - Rhai crate
* [`DOCS.RS`](https://docs.rs/rhai) - Rhai API documentation
@ -15,6 +15,6 @@ Other online documentation resources for Rhai:
Other cool projects to check out:
* [ChaiScript](http://chaiscript.com/) - A strong inspiration for Rhai. An embedded scripting language for C++ that I helped created many moons ago, now being led by my cousin.
* [ChaiScript](http://chaiscript.com) - A strong inspiration for Rhai. An embedded scripting language for C++.
* Check out the list of [scripting languages for Rust](https://github.com/rust-unofficial/awesome-rust#scripting) on [awesome-rust](https://github.com/rust-unofficial/awesome-rust)

View File

@ -10,3 +10,9 @@ The following targets and builds are support by Rhai:
* WebAssembly ([WASM])
* [`no-std`]
Minimum Rust Version
--------------------
The minimum version of Rust required to compile Rhai is `1.45.0`.

View File

@ -13,8 +13,6 @@ This section covers advanced features such as:
* [Script optimization].
* [Domain-Specific Languages][DSL].
* Low-level [function registration API]({{rootUrl}}/rust/register-raw.md)
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement.
* [Domain-Specific Languages][DSL].

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -49,8 +49,8 @@ f.call!(41); // <- syntax error: capturing is not allowed in method-c
No Mutations
------------
Variables in the calling scope are captured as copies.
Changes to them do not reflect back to the calling scope.
Variables in the calling scope are captured as cloned copies.
Changes to them do **not** reflect back to the calling scope.
Rhai functions remain _pure_ in the sense that they can never mutate their environment.

View File

@ -15,10 +15,10 @@ forming a new, combined, group of functions.
In general, there are two types of _namespaces_ where functions are looked up:
| Namespace | Source | Lookup method | How Many |
| --------- | ---------------------------------------------------------------------- | --------------------------------- | :----------------------: |
| Global | `Engine::register_XXX` API, [`AST`] being evaluated, [packages] loaded | simple function name | one |
| Module | [`Module`] | namespace-qualified function name | as many as [`import`]-ed |
| Namespace | Source | Lookup method | Sub-modules? | Variables? |
| --------- | ------------------------------------------------------------------------------------- | ------------------------------ | :----------: | :--------: |
| Global | 1) `Engine::register_XXX` API<br/>2) [`AST`] being evaluated<br/>3) [packages] loaded | simple function name | ignored | ignored |
| Module | [`Module`] | module-qualified function name | yes | yes |
Global Namespace

View File

@ -15,9 +15,10 @@ Built-in methods
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
using a [raw `Engine`]) operate on [strings]:
| Function | Parameter(s) | Description |
| -------------------------- | ------------ | --------------------------------------------------------------------- |
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
| Function | Parameter(s) | Description |
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
Examples
@ -143,7 +144,9 @@ to a function call while binding the object in the method call to the `this` poi
To achieve this, pass the `FnPtr` value as the _first_ argument to `call`:
```rust
fn add(x) { this += x; } // define function which uses 'this'
fn add(x) { // define function which uses 'this'
this += x;
}
let func = Fn("add"); // function pointer to 'add'

View File

@ -12,8 +12,13 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol
To loop through a number sequence (with or without steps), use the `range` function to
return a numeric iterator.
Iterate Through Strings
-----------------------
Iterating through a [string] yields characters.
```rust
// Iterate through string, yielding characters
let s = "hello, world!";
for ch in s {
@ -23,8 +28,15 @@ for ch in s {
if x == '@' { break; } // break out of for loop
}
```
// Iterate through array
Iterate Through Arrays
----------------------
Iterating through an [array] yields cloned _copies_ of each element.
```rust
let array = [1, 3, 5, 7, 9, 42];
for x in array {
@ -34,8 +46,17 @@ for x in array {
if x == 42 { break; } // break out of for loop
}
```
// The 'range' function allows iterating from first to last-1
Iterate Through Numeric Ranges
-----------------------------
The `range` function allows iterating through a range of numbers
(not including the last number).
```rust
// Iterate starting from 0 and stopping at 49.
for x in range(0, 50) {
if x > 10 { continue; } // skip to the next iteration
@ -44,7 +65,7 @@ for x in range(0, 50) {
if x == 42 { break; } // break out of for loop
}
// The 'range' function also takes a step
// The 'range' function also takes a step.
for x in range(0, 50, 3) { // step by 3
if x > 10 { continue; } // skip to the next iteration
@ -52,8 +73,18 @@ for x in range(0, 50, 3) { // step by 3
if x == 42 { break; } // break out of for loop
}
```
// Iterate through object map
Iterate Through Object Maps
--------------------------
Two functions, `keys` and `values`, return [arrays] containing cloned _copies_
of all property names and values of an [object map], respectively.
These [arrays] can be iterated.
```rust
let map = #{a:1, b:3, c:5, d:7, e:9};
// Property names are returned in unsorted, random order

View File

@ -42,19 +42,6 @@ add2(42) == 44;
```
No Access to External Scope
--------------------------
Functions are not _closures_. They do not capture the calling environment and can only access their own parameters.
They cannot access variables external to the function itself.
```rust
let x = 42;
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
```
Global Definitions Only
----------------------
@ -77,24 +64,52 @@ fn do_addition(x) {
```
Use Before Definition
--------------------
No Access to External Scope
--------------------------
Functions are not _closures_. They do not capture the calling environment
and can only access their own parameters.
They cannot access variables external to the function itself.
```rust
let x = 42;
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
```
But Can Call Other Functions
---------------------------
All functions in the same [`AST`] can call each other.
```rust
fn foo(x) { x + 1 } // function defined in the global namespace
fn bar(x) { foo(x) } // OK! function 'foo' can be called
```
Use Before Definition Allowed
----------------------------
Unlike C/C++, functions in Rhai can be defined _anywhere_ at global level.
A function does not need to be defined prior to being used in a script;
a statement in the script can freely call a function defined afterwards.
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
Arguments Passed by Value
------------------------
Arguments are Passed by Value
----------------------------
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
Functions defined in script always take [`Dynamic`] parameters (i.e. they can be of any types).
Therefore, functions with the same name and same _number_ of parameters are equivalent.
It is important to remember that all arguments are passed by _value_, so all Rhai script-defined functions
are _pure_ (i.e. they never modify their arguments).
All arguments are passed by _value_, so all Rhai script-defined functions are _pure_
(i.e. they never modify their arguments).
Any update to an argument will **not** be reflected back to the caller.
```rust
@ -113,8 +128,8 @@ x == 500; // 'x' is NOT changed!
`this` - Simulating an Object Method
-----------------------------------
Functions can also be called in method-call style. When this is the case, the keyword '`this`'
binds to the object in the method call and can be changed.
Script-defined functions can also be called in method-call style.
When this happens, the keyword '`this`' binds to the object in the method call and can be changed.
```rust
fn change() { // not that the object does not need a parameter

View File

@ -39,8 +39,8 @@ array[0].update(); // <- call in method-call style will update 'a'
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
Number of Parameters
--------------------
Number of Parameters in Methods
------------------------------
Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than
an equivalent method coded in script, where the object is accessed via the `this` pointer instead.
@ -53,15 +53,43 @@ The following table illustrates the differences:
| Rhai script | _N_ | `this` (of type `&mut T`) | `Fn(x: U, y: V)` |
`&mut` is Efficient, Except for `ImmutableString`
-----------------------------------------------
`&mut` is Efficient, Except for `&mut ImmutableString`
----------------------------------------------------
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
For example, the `len` method of an [array] has the signature: `Fn(&mut Array) -> INT`.
The array itself is not modified in any way, but using a `&mut` parameter avoids a cloning that would
otherwise have happened if the signature were `Fn(Array) -> INT`.
Even when a function is never intended to be a method - for example an operator,
it is still sometimes beneficial to make it method-like (i.e. with a first `&mut` parameter)
if the first parameter is not modified.
For types that are expensive to clone (remember, all function calls are passed cloned
copies of argument values), this may result in a significant performance boost.
For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`,
this is not necessary.
```rust
// This is a type that is very expensive to clone.
#[derive(Debug, Clone)]
struct VeryComplexType { ... }
// Calculate some value by adding 'VeryComplexType' with an integer number.
fn do_add(obj: &VeryComplexType, offset: i64) -> i64 {
...
}
engine
.register_type::<VeryComplexType>()
.register_fn("+", add_pure /* or add_method*/);
// Very expensive to call, as the 'VeryComplexType' is cloned before each call.
fn add_pure(obj: VeryComplexType, offset: i64) -> i64 {
do_add(obj, offset)
}
// Efficient to call, as only a reference to the 'VeryComplexType' is passed.
fn add_method(obj: &mut VeryComplexType, offset: i64) -> i64 {
do_add(obj, offset)
}
```

View File

@ -29,7 +29,15 @@ Modifying an `ImmutableString` causes it first to be cloned, and then the modifi
`ImmutableString` should be used in place of `String` for function parameters because using
`String` is very inefficient (the `String` argument is cloned during every call).
A alternative is to use `&str` which maps straight to `ImmutableString`.
A alternative is to use `&str` which de-sugars to `ImmutableString`.
```rust
fn slow(s: String) -> i64 { ... } // string is cloned each call
fn fast1(s: ImmutableString) -> i64 { ... } // cloning 'ImmutableString' is cheap
fn fast2(s: &str) -> i64 { ... } // de-sugars to above
```
String and Character Literals

View File

@ -16,8 +16,9 @@ if some_bad_condition_has_happened {
throw; // defaults to empty exception text: ""
```
Exceptions thrown via `throw` in the script can be captured by matching `Err(Box<EvalAltResult::ErrorRuntime(` _reason_ `,` _position_ `)>)`
with the exception text captured by the first parameter.
Exceptions thrown via `throw` in the script can be captured in Rust by matching
`Err(Box<EvalAltResult::ErrorRuntime(reason, position)>)` with the exception text
captured by `reason`.
```rust
let result = engine.eval::<i64>(r#"

View File

@ -46,15 +46,22 @@ struct Config {
### Make Shared Object
```rust
let config: Rc<RefCell<Config>> = Rc::new(RefCell::new(Default::default()));
pub type SharedConfig = Rc<RefCell<Config>>;
```
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
must then be `Send + Sync`.
```rust
let config: SharedConfig = Rc::new(RefCell::new(Default::default()));
```
### Register Config API
The trick to building a Config API is to clone the shared configuration object and
move it into each function registration as a closure.
move it into each function registration via a closure.
It is not possible to use a [plugin module] to achieve this, so each function must
Therefore, it is not possible to use a [plugin module] to achieve this, and each function must
be registered one after another.
```rust

View File

@ -35,7 +35,7 @@ but only through exposing an abstract API primarily made up of functions.
Use this when the API is relatively simple and clean, and the number of functions is small enough.
For a complex API involving lots of functions, or an API that is object-based,
For a complex API involving lots of functions, or an API that has a clear object structure,
use the [Singleton Command Object]({{rootUrl}}/patterns/singleton.md) pattern instead.
@ -59,15 +59,22 @@ impl EnergizerBunny {
### Wrap API in Shared Object
```rust
let bunny: Rc<RefCell<EnergizerBunny>> = Rc::new(RefCell::(EnergizerBunny::new()));
pub type SharedBunny = Rc<RefCell<EnergizerBunny>>;
```
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
must then be `Send + Sync`.
```rust
let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new()));
```
### Register Control API
The trick to building a Control API is to clone the shared API object and
move it into each function registration as a closure.
move it into each function registration via a closure.
It is not possible to use a [plugin module] to achieve this, so each function must
Therefore, it is not possible to use a [plugin module] to achieve this, and each function must
be registered one after another.
```rust

View File

@ -41,7 +41,7 @@ wrapping the system in a shared, interior-mutated object.
This is the other way which involves directly exposing the data structures of the external system
as a name singleton object in the scripting space.
Use this when the API is complex and clearly object-based.
Use this when the API is complex but has a clear object structure.
For a relatively simple API that is action-based and not object-based,
use the [Control Layer]({{rootUrl}}/patterns/control.md) pattern instead.
@ -68,13 +68,16 @@ impl EnergizerBunny {
### Wrap Command Object Type as Shared
```rust
let SharedBunnyType = Rc<RefCell<EnergizerBunny>>;
pub type SharedBunny = Rc<RefCell<EnergizerBunny>>;
```
Note: Use `Arc<Mutex<T>>` or `Arc<RwLock<T>>` when using the [`sync`] feature because the function
must then be `Send + Sync`.
### Register the Custom Type
```rust
engine.register_type_with_name::<SharedBunnyType>("EnergizerBunny");
engine.register_type_with_name::<SharedBunny>("EnergizerBunny");
```
### Develop a Plugin with Methods and Getters/Setters
@ -82,18 +85,18 @@ engine.register_type_with_name::<SharedBunnyType>("EnergizerBunny");
The easiest way to develop a complete set of API for a [custom type] is via a [plugin module].
```rust
use rhai::plugins::*;
use rhai::plugin::*;
#[export_module]
pub mod bunny_api {
pub const MAX_SPEED: i64 = 100;
#[rhai_fn(get = "power")]
pub fn get_power(bunny: &mut SharedBunnyType) -> bool {
pub fn get_power(bunny: &mut SharedBunny) -> bool {
bunny.borrow().is_going()
}
#[rhai_fn(set = "power")]
pub fn set_power(bunny: &mut SharedBunnyType, on: bool) {
pub fn set_power(bunny: &mut SharedBunny, on: bool) {
if on {
if bunny.borrow().is_going() {
println!("Still going...");
@ -109,7 +112,7 @@ pub mod bunny_api {
}
}
#[rhai_fn(get = "speed")]
pub fn get_speed(bunny: &mut SharedBunnyType) -> i64 {
pub fn get_speed(bunny: &mut SharedBunny) -> i64 {
if bunny.borrow().is_going() {
bunny.borrow().get_speed()
} else {
@ -117,7 +120,7 @@ pub mod bunny_api {
}
}
#[rhai_fn(set = "speed", return_raw)]
pub fn set_speed(bunny: &mut SharedBunnyType, speed: i64)
pub fn set_speed(bunny: &mut SharedBunny, speed: i64)
-> Result<Dynamic, Box<EvalAltResult>>
{
if speed <= 0 {
@ -131,12 +134,12 @@ pub mod bunny_api {
Ok(().into())
}
}
pub fn turn_left(bunny: &mut SharedBunnyType) {
pub fn turn_left(bunny: &mut SharedBunny) {
if bunny.borrow().is_going() {
bunny.borrow_mut().turn(true);
}
}
pub fn turn_right(bunny: &mut SharedBunnyType) {
pub fn turn_right(bunny: &mut SharedBunny) {
if bunny.borrow().is_going() {
bunny.borrow_mut().turn(false);
}
@ -149,7 +152,7 @@ engine.load_package(exported_module!(bunny_api));
### Push Constant Command Object into Custom Scope
```rust
let bunny: SharedBunnyType = Rc::new(RefCell::(EnergizerBunny::new()));
let bunny: SharedBunny = Rc::new(RefCell::(EnergizerBunny::new()));
let mut scope = Scope::new();

View File

@ -29,7 +29,7 @@ To register the plugin function, simply call `register_exported_fn!`. The name
any text string, so it is possible to register _overloaded_ functions as well as operators.
```rust
use rhai::plugins::*; // import macros
use rhai::plugin::*; // import macros
#[export_fn]
fn increment(num: &mut i64) {
@ -55,7 +55,7 @@ A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does n
have the appropriate return type.
```rust
use rhai::plugins::*; // import macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_fn]
#[rhai_fn(return_raw)]

View File

@ -9,5 +9,5 @@ functionality.
Instead of using the large `Engine::register_XXX` API or the parallel `Module::set_fn_XXX` API,
a _plugin_ simplifies the work of creating and registering new functionality in an [`Engine`].
Plugins are processed via a set of procedural macros under the `rhai::plugins` module. These
Plugins are processed via a set of procedural macros under the `rhai::plugin` module. These
allow registering Rust functions directly in the Engine, or adding Rust modules as packages.

View File

@ -4,6 +4,20 @@ Export a Rust Module to Rhai
{{#include ../links.md}}
Prelude
-------
When using the plugins system, the entire `rhai::plugin` module must be imported as a prelude
because code generated will these imports.
```rust
use rhai::plugin::*;
```
`#[export_module]` and `exported_module!`
----------------------------------------
When applied to a Rust module, the `#[export_module]` attribute generates the necessary
code and metadata to allow Rhai access to its public (i.e. marked `pub`) functions, constants
and sub-modules.
@ -14,18 +28,11 @@ and is custom fit to each exported item.
This Rust module can then either be loaded into an [`Engine`] as a normal [module] or
registered as a [custom package]. This is done by using the `exported_module!` macro.
`#[export_module]` and `exported_module!`
----------------------------------------
Apply `#[export_module]` onto a Rust module to register automatically construct a Rhai [module],
which can then be loaded into an [`Engine`].
All `pub` functions become registered functions, all `pub` constants become [module] constant variables,
and all sub-modules become Rhai sub-modules.
```rust
use rhai::plugins::*; // a "prelude" import for macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_module]
mod my_module {
@ -117,7 +124,7 @@ Operators (which require function names that are not valid for Rust) can also be
Registering the same function name with the same parameter types will cause a parsing error.
```rust
use rhai::plugins::*; // a "prelude" import for macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_module]
mod my_module {
@ -147,7 +154,7 @@ Functions can be marked as [getters/setters] and [indexers] for [custom types] v
attribute, which is applied on a function level.
```rust
use rhai::plugins::*; // a "prelude" import for macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_module]
mod my_module {
@ -188,7 +195,7 @@ This is especially useful for the `name = "..."`, `get = "..."` and `set = "..."
to give multiple alternative names to the same function.
```rust
use rhai::plugins::*; // a "prelude" import for macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_module]
mod my_module {
@ -221,7 +228,7 @@ A syntax error is generated if the function with `#[rhai_fn(return_raw)]` does n
have the appropriate return type.
```rust
use rhai::plugins::*; // a "prelude" import for macros
use rhai::plugin::*; // a "prelude" import for macros
#[export_module]
mod my_module {

View File

@ -3,8 +3,16 @@ Disable Custom Types
{{#include ../links.md}}
`no_object` Feature
-------------------
The custom types API `register_type`, `register_type_with_name`, `register_get`, `register_get_result`,
`register_set`, `register_set_result` and `register_get_set` are not available under [`no_object`].
`no_index` Feature
------------------
The indexers API `register_indexer_get`, `register_indexer_get_result`, `register_indexer_set`,
`register_indexer_set_result`, and `register_indexer_get_set` are also not available under [`no_index`].

View File

@ -11,7 +11,7 @@ Getters and setters are disabled when the [`no_object`] feature is used.
| `Engine` API | Description | Return Value of Function |
| --------------------- | ------------------------------------------------- | :-----------------------------------: |
| `register_get` | register a getter | _any_ |
| `register_get` | register a getter | _any_ `T: Clone` |
| `register_set` | register a setter | _none_ |
| `register_get_set` | short-hand to register both a getter and a setter | _none_ |
| `register_get_result` | register a getter | `Result<Dynamic, Box<EvalAltResult>>` |

View File

@ -15,7 +15,7 @@ Indexers are disabled when the [`no_index`] feature is used.
| `Engine` API | Description | Return Value of Function |
| ----------------------------- | -------------------------------------------------------- | :-----------------------------------: |
| `register_indexer_get` | register an index getter | _any_ |
| `register_indexer_get` | register an index getter | _any_ `T: Clone` |
| `register_indexer_set` | register an index setter | _none_ |
| `register_indexer_get_set` | short-hand to register both an index getter and a setter | _none_ |
| `register_indexer_get_result` | register an index getter | `Result<Dynamic, Box<EvalAltResult>>` |

View File

@ -6,16 +6,23 @@ Operator Overloading
In Rhai, a lot of functionalities are actually implemented as functions, including basic operations
such as arithmetic calculations.
For example, in the expression "`a + b`", the `+` operator is _not_ built in, but calls a function named "`+`" instead!
For example, in the expression "`a + b`", the `+` operator calls a function named "`+`"!
```rust
let x = a + b;
let x = +(a, b); // <- the above is equivalent to this function call
```
Similarly, comparison operators including `==`, `!=` etc. are all implemented as functions,
with the stark exception of `&&` and `||`. Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators),
`&&` and `||` are handled specially and _not_ via a function; as a result, overriding them has no effect at all.
with the stark exception of `&&` and `||`.
`&&` and `||` Cannot Be Overloaded
---------------------------------
Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators), `&&` and `||` are
handled specially and _not_ via a function; as a result, overriding them has no effect at all.
Overload Operator via Rust Function

View File

@ -60,7 +60,7 @@ 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::plugins::combine_with_exported_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].
In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented.
@ -113,8 +113,8 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
//
// The sub-module 'my_sub_module' is flattened and its functions registered at the top level.
//
// The text string name in the middle parameter can be anything and is reserved for future use;
// it is recommended to be an ID string that uniquely identifies the module.
// 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.
//

View File

@ -3,7 +3,8 @@ Load a Plugin Module as a Package
{{#include ../../links.md}}
[Plugin modules] can be loaded as a package just like a normal [module].
[Plugin modules] can be loaded as a package just like a normal [module]
via the `exported_module!` macro.
```rust
use rhai::Engine;

View File

@ -35,13 +35,12 @@ engine.register_raw_fn(
// Therefore, get a '&mut' reference to the first argument _last_.
// Alternatively, use `args.split_first_mut()` etc. to split the slice first.
let y: i64 = *args[1].read_lock::<i64>() // get a reference to the second argument
.unwrap(); // then copying it because it is a primary type
let y = *args[1].read_lock::<i64>().unwrap(); // get a reference to the second argument
// then copy it because it is a primary type
let y: i64 = std::mem::take(args[1]).cast::<i64>(); // alternatively, directly 'consume' it
let y = std::mem::take(args[1]).cast::<i64>(); // alternatively, directly 'consume' it
let x: &mut i64 = args[0].write_lock::<i64>() // get a '&mut' reference to the
.unwrap(); // first argument
let x = args[0].write_lock::<i64>().unwrap(); // get a '&mut' reference to the first argument
*x += y; // perform the action
@ -51,7 +50,7 @@ engine.register_raw_fn(
// The above is the same as (in fact, internally they are equivalent):
engine.register_fn("increment_by", |x: &mut i64, y: i64| x += y);
engine.register_fn("increment_by", |x: &mut i64, y: i64| *x += y);
```
@ -153,7 +152,8 @@ is a _shared value_ created by [capturing][automatic currying] variables from [c
Shared values are implemented as `Rc<RefCell<Dynamic>>` (`Arc<RwLock<Dynamic>>` under [`sync`]).
If the value is _not_ a shared value, or if running under [`no_closure`] where there is
no [capturing][automatic currying], this API de-sugars to a simple `downcast_ref` and `downcast_mut`.
no [capturing][automatic currying], this API de-sugars to a simple `Dynamic::downcast_ref` and
`Dynamic::downcast_mut`.
If the value is a shared value, then it is first locked and the returned lock guard
then allows access to the underlying value in the specified type.
@ -171,9 +171,9 @@ to partition the slice:
let (first, rest) = args.split_first_mut().unwrap();
// Mutable reference to the first parameter
let this_ptr: &mut A = &mut *first.write_lock::<A>().unwrap();
let this_ptr = &mut *first.write_lock::<A>().unwrap();
// Immutable reference to the second value parameter
// This can be mutable but there is no point because the parameter is passed by value
let value_ref: &B = &*rest[0].read_lock::<B>().unwrap();
let value_ref = &*rest[0].read_lock::<B>().unwrap();
```

View File

@ -5,9 +5,10 @@ Traits
A number of traits, under the `rhai::` module namespace, provide additional functionalities.
| Trait | Description | Methods |
| ------------------ | ---------------------------------------------------------------------------------------- | --------------------------------------- |
| `RegisterFn` | trait for registering functions | `register_fn` |
| `RegisterResultFn` | trait for registering fallible functions returning `Result<Dynamic, Box<EvalAltResult>>` | `register_result_fn` |
| `Func` | trait for creating Rust closures from script | `create_from_ast`, `create_from_script` |
| `ModuleResolver` | trait implemented by module resolution services | `resolve` |
| Trait | Description | Methods |
| ------------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------- |
| `RegisterFn` | trait for registering functions | `register_fn` |
| `RegisterResultFn` | trait for registering [fallible functions] | `register_result_fn` |
| `Func` | trait for creating Rust closures from script | `create_from_ast`, `create_from_script` |
| `ModuleResolver` | trait implemented by [module resolution][module resolver] services | `resolve` |
| `plugin::PluginFunction` | trait implemented by [plugin] functions | `call`, `is_method_call`, `is_variadic`, `clone_boxed`, `input_types` |