...
This commit is contained in:
121
rhai_engine/rhaibook/start/bin.md
Normal file
121
rhai_engine/rhaibook/start/bin.md
Normal file
@@ -0,0 +1,121 @@
|
||||
Packaged Utilities
|
||||
==================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
A number of Rhai-driven tools can be found in the `src/bin` directory:
|
||||
|
||||
```admonish tip.side "Tip: Domain-specific tools"
|
||||
|
||||
It is possible to turn these tools into [_Domain-Specific Tools_](../patterns/domain-tools.md).
|
||||
```
|
||||
|
||||
| Tool | Required feature(s) | Description |
|
||||
| :----------------------------------------------: | :-----------------: | ---------------------- |
|
||||
| [`rhai-run`]({{repoHome}}/src/bin/rhai-run.rs) | | runs Rhai script files |
|
||||
| [`rhai-repl`]({{repoHome}}/src/bin/rhai-repl.rs) | `rustyline` | a simple REPL tool |
|
||||
| [`rhai-dbg`]({{repoHome}}/src/bin/rhai-dbg.rs) | [`debugging`] | the _Rhai Debugger_ |
|
||||
|
||||
~~~admonish tip "Tip: `bin-features`"
|
||||
Some bin tools require certain [features] and will not be built by default without those [features] set.
|
||||
|
||||
For convenience, a feature named [`bin-features`][features] is available which is a combination of
|
||||
the following:
|
||||
|
||||
| Feature | Description |
|
||||
| :-----------: | ------------------------------------------- |
|
||||
| [`decimal`] | support for [decimal][rust_decimal] numbers |
|
||||
| [`metadata`] | access [functions metadata] |
|
||||
| [`serde`] | export [functions metadata] to JSON |
|
||||
| [`debugging`] | required by `rhai-dbg` |
|
||||
| `rustyline` | required by `rhai-repl` |
|
||||
~~~
|
||||
|
||||
|
||||
Install Tools
|
||||
-------------
|
||||
|
||||
To install all these tools (with full features), use the following command:
|
||||
|
||||
```sh
|
||||
cargo install --path . --bins --features bin-features
|
||||
```
|
||||
|
||||
or specifically:
|
||||
|
||||
```sh
|
||||
cargo install --path . --bin sample_app_to_run --features bin-features
|
||||
```
|
||||
|
||||
|
||||
Run a Tool from Cargo
|
||||
---------------------
|
||||
|
||||
Tools can also be run with the following `cargo` command:
|
||||
|
||||
```sh
|
||||
cargo run --features bin-features --bin sample_app_to_run
|
||||
```
|
||||
|
||||
|
||||
Tools List
|
||||
----------
|
||||
|
||||
~~~admonish example "`rhai-repl` – The Rhai REPL Tool"
|
||||
|
||||
`rhai-repl` is a particularly useful tool – it allows one to interactively try out
|
||||
Rhai's language features in a standard REPL (**R**ead-**E**val-**P**rint **L**oop).
|
||||
|
||||
Filenames passed to it as command line arguments are run and loaded as Rhai scripts before the REPL starts.
|
||||
|
||||
### Test functions
|
||||
|
||||
The following test functions are pre-registered, via `Engine::register_fn`, into `rhai-repl`.
|
||||
They are intended for testing purposes.
|
||||
|
||||
| Function | Description |
|
||||
| ------------------------------------ | ------------------------------------------ |
|
||||
| `test(x: i64, y: i64)` | returns a string with both numbers |
|
||||
| `test(x: &mut i64, y: i64, z: &str)` | displays the parameters and add `y` to `x` |
|
||||
|
||||
### Example
|
||||
|
||||
The following command first runs three scripts – `init1.rhai`, `init2.rhai` and `init3.rhai` –
|
||||
loading the functions defined in each script into the _global_ namespace.
|
||||
|
||||
Then it enters an REPL, which can call the above functions freely.
|
||||
|
||||
```sh
|
||||
rhai-repl init1.rhai init2.rhai init3.rhai
|
||||
```
|
||||
~~~
|
||||
|
||||
~~~admonish danger "`rhai-run` – The Rhai Runner"
|
||||
|
||||
Use `rhai-run` to run Rhai scripts.
|
||||
|
||||
Filenames passed to it as command line arguments are run in sequence as Rhai scripts.
|
||||
|
||||
### Example
|
||||
|
||||
The following command runs the scripts `script1.rhai`, `script2.rhai` and `script3.rhai` in order.
|
||||
|
||||
```sh
|
||||
rhai-run script1.rhai script2.rhai script3.rhai
|
||||
```
|
||||
~~~
|
||||
|
||||
~~~admonish bug "`rhai-dbg` – The Rhai Debugger"
|
||||
|
||||
Use `rhai-dbg` to debug a Rhai script.
|
||||
|
||||
Filename passed to it will be loaded as a Rhai script for debugging.
|
||||
|
||||
### Example
|
||||
|
||||
The following command debugs the script `my_script.rhai`.
|
||||
|
||||
```sh
|
||||
rhai-dbg my_script.rhai
|
||||
```
|
||||
~~~
|
7
rhai_engine/rhaibook/start/builds/index.md
Normal file
7
rhai_engine/rhaibook/start/builds/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Special Builds
|
||||
==============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
It is possible to mix-and-match various [features] of the Rhai crate to make specialized builds with
|
||||
specific characteristics and behaviors.
|
67
rhai_engine/rhaibook/start/builds/minimal.md
Normal file
67
rhai_engine/rhaibook/start/builds/minimal.md
Normal file
@@ -0,0 +1,67 @@
|
||||
Minimal Build
|
||||
=============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
In order to compile a _minimal_ build – i.e. a build optimized for size – perhaps for
|
||||
`no-std` embedded targets or for compiling to [WASM], it is essential that the correct linker flags
|
||||
are used in `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[profile.release]
|
||||
lto = "fat" # turn on Link-Time Optimizations
|
||||
codegen-units = 1 # trade compile time with maximum optimization
|
||||
opt-level = "z" # optimize for size
|
||||
```
|
||||
|
||||
|
||||
Use `i32` Only
|
||||
--------------
|
||||
|
||||
For embedded systems that must optimize for code size, the architecture is commonly 32-bit.
|
||||
Use [`only_i32`] to prune away large sections of code implementing functions for other numeric types
|
||||
(including `i64`).
|
||||
|
||||
If, for some reason, 64-bit long integers must be supported, use [`only_i64`] instead of [`only_i32`].
|
||||
|
||||
|
||||
Opt-Out of Features
|
||||
-------------------
|
||||
|
||||
Opt out of as many features as possible, if they are not needed, to reduce code size because,
|
||||
remember, by default all code is compiled into the final binary since what a script requires cannot
|
||||
be predicted. If a language feature will never be needed, omitting it is a prudent strategy to
|
||||
optimize the build for size.
|
||||
|
||||
Removing the script [optimizer][script optimization] ([`no_optimize`]) yields a sizable code saving,
|
||||
at the expense of a less efficient script.
|
||||
|
||||
Omitting [arrays] ([`no_index`]) yields the most code-size savings, followed by floating-point support
|
||||
([`no_float`]), safety checks ([`unchecked`]) and finally [object maps] and [custom types] ([`no_object`]).
|
||||
|
||||
Where the usage scenario does not call for loading externally-defined modules, use [`no_module`] to
|
||||
save some bytes. Disable script-defined functions ([`no_function`]) and possibly closures
|
||||
([`no_closure`]) when the features are not needed. Both of these have some code size savings but not much.
|
||||
|
||||
For embedded scripts that are not expected to cause errors, the [`no_position`] feature can be used
|
||||
to disable position tracking during parsing. No line number/character position information is kept
|
||||
for error reporting purposes. This may result in a slightly smaller build due to elimination of code
|
||||
related to position tracking.
|
||||
|
||||
|
||||
Use a Raw [`Engine`]
|
||||
--------------------
|
||||
|
||||
[`Engine::new_raw`][raw `Engine`] creates a _raw_ engine. A _raw_ engine supports, out of the box,
|
||||
only a very [restricted set][built-in operators] of basic arithmetic and logical operators.
|
||||
|
||||
Selectively include other necessary functionalities by picking specific [packages] to minimize the footprint.
|
||||
|
||||
Packages are shared (even across threads via the [`sync`] feature), so they only have to be created once.
|
||||
|
||||
In addition, a [`Engine::new_raw`][raw `Engine`] disables the _[strings interner]_, which might
|
||||
actually increase memory usage if many strings are created in scripts. Therefore, selectively turn
|
||||
on the [strings interner] via [`Engine::set_max_strings_interned`][options].
|
80
rhai_engine/rhaibook/start/builds/no-std.md
Normal file
80
rhai_engine/rhaibook/start/builds/no-std.md
Normal file
@@ -0,0 +1,80 @@
|
||||
`no-std` Build
|
||||
==============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
The feature [`no_std`] automatically converts the scripting engine into a `no-std` build.
|
||||
|
||||
Usually, a `no-std` build goes hand-in-hand with [minimal builds] because typical embedded
|
||||
hardware (the primary target for `no-std`) has limited storage.
|
||||
|
||||
```admonish warning "Nightly required"
|
||||
|
||||
Currently, [`no_std`] requires the nightly compiler due to the crates that it uses.
|
||||
```
|
||||
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
Rhai allocates, so the first thing that must be included in any `no-std` project is
|
||||
an allocator crate, such as [`wee_alloc`](https://crates.io/crates/wee_alloc).
|
||||
|
||||
Then there is the need to set up proper error/panic handlers.
|
||||
The following example uses `panic = "abort"` and `wee_alloc` as the allocator.
|
||||
|
||||
```rust
|
||||
// Set up for no-std.
|
||||
#![no_std]
|
||||
|
||||
// The following no-std features are usually needed.
|
||||
#![feature(alloc_error_handler, start, core_intrinsics, lang_items, link_cfg)]
|
||||
|
||||
// Set up the global allocator.
|
||||
extern crate alloc;
|
||||
extern crate wee_alloc;
|
||||
|
||||
#[global_allocator]
|
||||
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
|
||||
|
||||
// Rust needs a CRT runtime on Windows when compiled with MSVC.
|
||||
#[cfg(all(windows, target_env = "msvc"))]
|
||||
#[link(name = "msvcrt")]
|
||||
#[link(name = "libcmt")]
|
||||
extern "C" {}
|
||||
|
||||
// Set up panic and error handlers
|
||||
#[alloc_error_handler]
|
||||
fn err_handler(_: core::alloc::Layout) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[panic_handler]
|
||||
#[lang = "panic_impl"]
|
||||
extern "C" fn rust_begin_panic(_: &core::panic::PanicInfo) -> ! {
|
||||
core::intrinsics::abort();
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"]
|
||||
extern "C" fn eh_personality() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_register_frames() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn rust_eh_unregister_frames() {}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn _Unwind_Resume() {}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
// ... main program ...
|
||||
}
|
||||
```
|
||||
|
||||
```admonish example.small "Samples"
|
||||
|
||||
Check out the [`no-std` sample applications]({{rootUrl}}/start/examples/rust.html#no-std-examples)
|
||||
for different operating environments.
|
||||
```
|
204
rhai_engine/rhaibook/start/builds/performance.md
Normal file
204
rhai_engine/rhaibook/start/builds/performance.md
Normal file
@@ -0,0 +1,204 @@
|
||||
Performance Build
|
||||
=================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
|
||||
Some features are for performance. In order to squeeze out the maximum performance from Rhai, the
|
||||
following features should be considered:
|
||||
|
||||
| Feature | Description | Rationale |
|
||||
| -------------------- | ------------------------------------------------------ | ------------------------ |
|
||||
| [`only_i32`] | support only a single `i32` integer type | reduce data size |
|
||||
| [`no_float`] | remove support for floating-point numbers | reduce code size |
|
||||
| [`f32_float`] | set floating-point numbers (if not disabled) to 32-bit | reduce data size |
|
||||
| [`no_closure`] | remove support for [variables] sharing | no need for data locking |
|
||||
| [`unchecked`] | disable all safety [checks][checked] | remove checking code |
|
||||
| [`no_module`] | disable loading external [modules] | reduce code size |
|
||||
| [`no_position`] | disable position tracking during parsing | reduce data size |
|
||||
| [`no_custom_syntax`] | disable [custom syntax] | reduce code size |
|
||||
|
||||
When the above feature flags are used, performance may increase by around 15-20%.
|
||||
|
||||
~~~admonish info.small "See also: Benchmarks"
|
||||
|
||||
See Rhai performance [benchmarks].
|
||||
~~~
|
||||
|
||||
|
||||
Unchecked Build
|
||||
---------------
|
||||
|
||||
By default, Rhai provides a [_Don't Panic_](https://en.wikipedia.org/wiki/Phrases_from_The_Hitchhiker%27s_Guide_to_the_Galaxy#Don't_Panic)
|
||||
guarantee and prevents malicious scripts from bringing down the host. Any panic can be considered a bug.
|
||||
|
||||
For maximum performance, however, these [safety] checks can be turned off via the [`unchecked`] feature.
|
||||
|
||||
|
||||
Fast Operators Mode
|
||||
-------------------
|
||||
|
||||
Make sure that [_Fast Operators_ Mode][options], which is enabled by default, is on. It ignores any
|
||||
user [overloading][operator overloading] of [built-in operators].
|
||||
|
||||
For operator-heavy scripts, this may provide a substantial speed-up.
|
||||
|
||||
|
||||
Use Only One Integer Type
|
||||
-------------------------
|
||||
|
||||
If only a single integer type is needed in scripts – most of the time this is the case –
|
||||
it is best to avoid registering lots of functions related to other integer types that will never be used.
|
||||
As a result, [`Engine`] creation will be faster because fewer functions need to be loaded.
|
||||
|
||||
The [`only_i32`] and [`only_i64`] features disable all integer types except `i32` or `i64` respectively.
|
||||
|
||||
|
||||
Use Only 32-Bit Numbers
|
||||
-----------------------
|
||||
|
||||
If only 32-bit integers are needed – again, most of the time this is the case – turn on [`only_i32`].
|
||||
Under this feature, only `i32` is supported as a built-in integer type and no others.
|
||||
|
||||
On 64-bit targets this may not gain much, but on certain 32-bit targets this improves performance
|
||||
due to 64-bit arithmetic requiring more CPU cycles to complete.
|
||||
|
||||
|
||||
Minimize Size of `Dynamic`
|
||||
--------------------------
|
||||
|
||||
Turning on [`f32_float`] (or [`no_float`]) and [`only_i32`] on 32-bit targets makes the critical
|
||||
[`Dynamic`] data type only 8 bytes long for 32-bit targets.
|
||||
|
||||
Normally [`Dynamic`] needs to be up 12-16 bytes long in order to hold an `i64` or `f64`.
|
||||
|
||||
A smaller [`Dynamic`] helps performance due to better cache efficiency.
|
||||
|
||||
|
||||
Use `ImmutableString`
|
||||
---------------------
|
||||
|
||||
Internally, Rhai uses _immutable_ [strings] instead of the Rust `String` type.
|
||||
This is mainly to avoid excessive cloning when passing function arguments.
|
||||
|
||||
Rhai's internal string type is [`ImmutableString`] (basically `Rc<SmartString>` or
|
||||
`Arc<SmartString>` depending on the [`sync`] feature). It is cheap to clone, but expensive to modify
|
||||
(a new copy of the string must be made in order to change it).
|
||||
|
||||
Therefore, functions taking `String` parameters should use [`ImmutableString`] or `&str`
|
||||
(maps to [`ImmutableString`]) for the best performance with Rhai.
|
||||
|
||||
|
||||
Disable Capturing in Closures
|
||||
-----------------------------
|
||||
|
||||
```admonish info.side "Anonymous functions still work"
|
||||
|
||||
[Anonymous functions] continue to work even under [`no_closure`].
|
||||
|
||||
Only capturing of external shared [variables] is disabled.
|
||||
```
|
||||
|
||||
Support for [closures] that capture _shared_ [variables] adds material overhead to script evaluation.
|
||||
|
||||
This is because every data access must be checked whether it is a shared value and, if so,
|
||||
take a read lock before reading it.
|
||||
|
||||
As the vast majority of [variables] are _not_ shared, needless to say this is a non-trivial
|
||||
performance overhead.
|
||||
|
||||
Use [`no_closure`] to disable support for [closures] to optimize the hot path because it no longer
|
||||
needs to take locks for shared data.
|
||||
|
||||
|
||||
Disable Position
|
||||
----------------
|
||||
|
||||
For embedded scripts that are not expected to cause errors, the [`no_position`] feature can be used
|
||||
to disable position tracking during parsing.
|
||||
|
||||
No line number/character position information is kept for error reporting purposes.
|
||||
|
||||
This may result in a slightly fast build due to elimination of code related to position tracking.
|
||||
|
||||
|
||||
Avoid Cloning
|
||||
-------------
|
||||
|
||||
### Use `&mut` functions
|
||||
|
||||
Rhai values are typically _cloned_ when passed around, especially into [function] calls.
|
||||
Large data structures may incur material cloning overhead.
|
||||
|
||||
Some functions accept the first parameter as a mutable reference (i.e. `&mut`), for example
|
||||
_methods_ for [custom types], and may avoid potentially-costly cloning.
|
||||
|
||||
### Compound assignment
|
||||
|
||||
For example, the `+=` (append) compound assignment takes a mutable reference to the [variable] while
|
||||
the corresponding `+` (add) assignment usually doesn't. The difference in performance can be huge:
|
||||
|
||||
```rust
|
||||
let x = create_some_very_big_and_expensive_type();
|
||||
|
||||
x = x + 1;
|
||||
// ^ 'x' is cloned here
|
||||
|
||||
// The above is equivalent to:
|
||||
let temp_value = x.clone() + 1;
|
||||
x = temp_value;
|
||||
|
||||
x += 1; // <- 'x' is NOT cloned
|
||||
```
|
||||
|
||||
### Use `take`
|
||||
|
||||
Another example: use the `take` function to extract a value out of a variable (replacing it with
|
||||
[`()`]) without cloning.
|
||||
|
||||
```rust
|
||||
let x = create_some_very_big_and_expensive_type();
|
||||
|
||||
let y = x; // <- 'x' is cloned here
|
||||
|
||||
let y = x.take(); // <- 'x' is NOT cloned
|
||||
```
|
||||
|
||||
```admonish tip "Tip: Simple variable references are already optimized"
|
||||
|
||||
Rhai's script [optimizer][script optimization] is usually smart enough to _rewrite_ function calls
|
||||
into [_method-call_]({{rootUrl}}/rust/methods.md) style or [_compound assignment_]({{rootUrl}}/language/assignment-op.md)
|
||||
style to take advantage of this.
|
||||
|
||||
However, there are limits to its intelligence, and only **simple variable references** are optimized.
|
||||
|
||||
~~~rust
|
||||
x = x + 1; // <- this statement...
|
||||
|
||||
x += 1; // ... is rewritten as this
|
||||
|
||||
x[y] = x[y] + 1; // <- but this is not, so this is MUCH slower...
|
||||
|
||||
x[y] += 1; // ... than this
|
||||
|
||||
some_func(x, 1); // <- this statement...
|
||||
|
||||
x.some_func(1); // ... is rewritten as this
|
||||
|
||||
some_func(x[y], 1); // <- but this is not, so 'x[y]` is cloned
|
||||
~~~
|
||||
```
|
||||
|
||||
|
||||
Short Variable Names for 32-Bit Systems
|
||||
---------------------------------------
|
||||
|
||||
On 32-bit systems, [variable] and [constant] names longer than 11 ASCII characters incur additional
|
||||
allocation overhead.
|
||||
|
||||
This is particularly true for local variables inside a hot loop, where they are created and destroyed
|
||||
in rapid succession.
|
||||
|
||||
Therefore, avoid long [variable] and [constant] names that are over this limit.
|
||||
|
||||
On 64-bit systems, this limit is raised to 23 ASCII characters, which is almost always adequate.
|
116
rhai_engine/rhaibook/start/builds/wasm.md
Normal file
116
rhai_engine/rhaibook/start/builds/wasm.md
Normal file
@@ -0,0 +1,116 @@
|
||||
WebAssembly (WASM) Build
|
||||
========================
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
```admonish question.side.wide "But why?"
|
||||
|
||||
There is already a fast and powerful scripting language that integrates nicely with WASM – **JavaScript**.
|
||||
|
||||
Anyhow, do it because you _can_!
|
||||
```
|
||||
|
||||
It is possible to use Rhai when compiling to WebAssembly (WASM).
|
||||
|
||||
This yields a scripting engine (and language) that can be run in a standard web browser,
|
||||
among other places.
|
||||
|
||||
```admonish warning "Unavailable features"
|
||||
|
||||
When building for WASM, certain features will not be available,
|
||||
such as the script file APIs and loading [modules] from external script files.
|
||||
```
|
||||
|
||||
```admonish example "Sample"
|
||||
|
||||
Check out the [_Online Playground_]({{rootUrl}}/tools/playground.md) project which is driven
|
||||
by a Rhai [`Engine`] compiled into WASM.
|
||||
```
|
||||
|
||||
|
||||
JavaScript Interop
|
||||
------------------
|
||||
|
||||
Specify either of the [`wasm-bindgen`] or [`stdweb`] features when building for WASM that requires
|
||||
interop with JavaScript. This selects the appropriate JavaScript interop layer to use.
|
||||
|
||||
It is still possible to compile for WASM without either [`wasm-bindgen`] or [`stdweb`],
|
||||
but then the interop code must then be explicitly provided.
|
||||
|
||||
|
||||
Target Environments
|
||||
-------------------
|
||||
|
||||
~~~admonish abstract "WASI: `wasm32-wasi`"
|
||||
|
||||
There is no particular setting to tweak when building for WASI.
|
||||
~~~
|
||||
|
||||
~~~admonish abstract "JavaScript: `wasm32-unknown-unknown` + `wasm-bindgen`/`stdweb`"
|
||||
|
||||
Rhai requires a system-provided source of random numbers (for hashing).
|
||||
|
||||
Such random number source is available from JavaScript (implied by `wasm-bindgen` or `stdweb`).
|
||||
|
||||
The `js` feature on the [`getrandom`](https://crates.io/crates/getrandom) crate is
|
||||
enabled automatically to provide the random number source.
|
||||
See also: <https://docs.rs/getrandom/latest/getrandom/#webassembly-support> for details.
|
||||
~~~
|
||||
|
||||
~~~admonish warning "Raw: `wasm32-unknown-unknown`"
|
||||
|
||||
Rhai requires a system-provided source of random numbers (for hashing).
|
||||
|
||||
Non-JavaScript/non-browser environments may not have random numbers available, so it is necessary to
|
||||
opt out of `default-features` in order to enable [static hashing] which uses fixed (non-random) keys.
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = { version = "{{version}}", default-features = false, features = [ "std" ] }
|
||||
```
|
||||
~~~
|
||||
|
||||
|
||||
Size
|
||||
----
|
||||
|
||||
Also look into [minimal builds] to reduce generated WASM size.
|
||||
|
||||
A typical, full-featured Rhai scripting engine compiles to a single WASM32 file that is less than
|
||||
400KB (non-gzipped).
|
||||
|
||||
When excluding features that are marginal in WASM environment, the gzipped payload can be shrunk further.
|
||||
|
||||
Standard [packages][built-in packages] can also be excluded to yield additional size savings.
|
||||
|
||||
|
||||
Speed
|
||||
-----
|
||||
|
||||
In benchmark tests, a WASM build runs scripts roughly 30% slower than a native optimized release build.
|
||||
|
||||
|
||||
Common Features
|
||||
---------------
|
||||
|
||||
Some Rhai functionalities are not necessary in a WASM environment, so the following features
|
||||
are typically used for a WASM build:
|
||||
|
||||
| Feature | Description |
|
||||
| :----------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`wasm-bindgen`] or [`stdweb`] | use [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) or [`stdweb`](https://crates.io/crates/stdweb) as the JavaScript interop layer, omit if using custom interop code |
|
||||
| [`unchecked`] | when a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely – the web app must terminate it itself |
|
||||
| [`only_i32`] | WASM supports 32-bit and 64-bit integers, but most scripts will only need 32-bit |
|
||||
| [`f32_float`] | WASM supports 32-bit single-precision and 64-bit double-precision floating-point numbers, but single-precision is usually fine for most uses |
|
||||
| [`no_module`] | a WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts |
|
||||
| [`no_custom_syntax`] | if [custom syntax] is not used, this results in a small size saving |
|
||||
|
||||
The following features are typically _not_ used because they don't make sense in a WASM build:
|
||||
|
||||
| Feature | Why unnecessary |
|
||||
| :-----------: | ----------------------------------------------------------------------------------------------------- |
|
||||
| [`sync`] | WASM is single-threaded |
|
||||
| [`no_std`] | `std` lib works fine with WASM |
|
||||
| [`metadata`] | WASM usually doesn't need access to Rhai functions metadata |
|
||||
| [`internals`] | WASM usually doesn't need to access Rhai internal data structures, unless you are walking the [`AST`] |
|
||||
| [`debugging`] | unless debugging is needed |
|
7
rhai_engine/rhaibook/start/examples/index.md
Normal file
7
rhai_engine/rhaibook/start/examples/index.md
Normal file
@@ -0,0 +1,7 @@
|
||||
Examples
|
||||
========
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Rhai comes with a number of examples showing how to integrate the scripting [`Engine`] within a Rust
|
||||
application, as well as a number of sample scripts that showcase different Rhai language features.
|
73
rhai_engine/rhaibook/start/examples/rust.md
Normal file
73
rhai_engine/rhaibook/start/examples/rust.md
Normal file
@@ -0,0 +1,73 @@
|
||||
Rust Examples
|
||||
=============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
|
||||
Standard Examples
|
||||
-----------------
|
||||
|
||||
A number of examples can be found under `examples`.
|
||||
|
||||
| Example | Description |
|
||||
| ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| [`arrays_and_structs`]({{repoHome}}/examples/arrays_and_structs.rs) | shows how to register a [Rust type][custom type] and using it with [arrays] |
|
||||
| [`callback`]({{repoHome}}/examples/callback.rs) | shows how to store a Rhai [closure] and call it later within Rust |
|
||||
| [`custom_types_and_methods`]({{repoHome}}/examples/custom_types_and_methods.rs) | shows how to register a [Rust type][custom type] and [methods]/[getters/setters] for it |
|
||||
| [`custom_types`]({{repoHome}}/examples/custom_types.rs) | shows how to register a [Rust type][custom type] and [methods]/[getters/setters] using the [`CustomType`] trait. |
|
||||
| [`definitions`]({{repoHome}}/examples/definitions) | shows how to generate definition files for use with the [Rhai Language Server][lsp] (requires the [`metadata`] feature) |
|
||||
| [`hello`]({{repoHome}}/examples/hello.rs) | simple example that evaluates an expression and prints the result |
|
||||
| [`pause_and_resume`]({{repoHome}}/pause_and_resume.rs) | shows how to pause/resume/stop an `Engine` running in a separate thread via an MPSC channel |
|
||||
| [`reuse_scope`]({{repoHome}}/examples/reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common [`Scope`] |
|
||||
| [`serde`]({{repoHome}}/examples/serde.rs) | example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde) (requires the [`serde`] feature) |
|
||||
| [`simple_fn`]({{repoHome}}/examples/simple_fn.rs) | shows how to register a simple Rust function |
|
||||
| [`strings`]({{repoHome}}/examples/strings.rs) | shows different ways to register Rust functions taking [string] arguments |
|
||||
| [`threading`]({{repoHome}}/examples/threading.rs) | shows how to communicate in duplex with an [`Engine`] running in a separate thread via a pair of MPSC channels |
|
||||
|
||||
|
||||
Scriptable Event Handler With State Examples
|
||||
--------------------------------------------
|
||||
|
||||
Because of its popularity, the pattern [_Scriptable Event Handler With State_]({{rootUrl}}/patterns/events.md)
|
||||
has sample implementations for different styles.
|
||||
|
||||
| Example | Handler Script | Description |
|
||||
| ---------------------------------------------------------------- | ---------------------------------------------------------------------------------------- | :----------------------------------------------: |
|
||||
| [`event_handler_main`]({{repoHome}}/examples/event_handler_main) | [`event_handler_main/script.rhai`]({{repoHome}}/examples/event_handler_main/script.rhai) | [_Main Style_]({{rootUrl}}/patterns/events-1.md) |
|
||||
| [`event_handler_js`]({{repoHome}}/examples/event_handler_js) | [`event_handler_js/script.rhai`]({{repoHome}}/examples/event_handler_js/script.rhai) | [_JS Style_]({{rootUrl}}/patterns/events-2.md) |
|
||||
| [`event_handler_map`]({{repoHome}}/examples/event_handler_map) | [`event_handler_map/script.rhai`]({{repoHome}}/examples/event_handler_map/script.rhai) | [_Map Style_]({{rootUrl}}/patterns/events-3.md) |
|
||||
|
||||
|
||||
Running Examples
|
||||
----------------
|
||||
|
||||
Examples can be run with the following command:
|
||||
|
||||
```sh
|
||||
cargo run --example {example_name}
|
||||
```
|
||||
|
||||
`no-std` Examples
|
||||
-----------------
|
||||
|
||||
To illustrate `no-std` builds, a number of example applications are available under the `no_std` directory:
|
||||
|
||||
| Example | Description | Optimization | Allocator | Panics |
|
||||
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------- | :----------: | :-----------------------------------------------: | :----: |
|
||||
| [`no_std_test`]({{repoHome}}/no_std/no_std_test) | bare-bones test application that evaluates a Rhai expression and sets the result as the return value | size | [`wee_alloc`](https://crates.io/crates/wee_alloc) | abort |
|
||||
|
||||
|
||||
### Building the `no-std` examples
|
||||
|
||||
```admonish warning "Nightly required"
|
||||
|
||||
Currently, the nightly compiler must be used to build for `no-std`.
|
||||
```
|
||||
|
||||
```sh
|
||||
cd no_std/no_std_test
|
||||
|
||||
cargo +nightly build --release
|
||||
|
||||
./target/release/no_std_test
|
||||
```
|
59
rhai_engine/rhaibook/start/examples/scripts.md
Normal file
59
rhai_engine/rhaibook/start/examples/scripts.md
Normal file
@@ -0,0 +1,59 @@
|
||||
Example Scripts
|
||||
===============
|
||||
|
||||
{{#include ../../links.md}}
|
||||
|
||||
Language Feature Scripts
|
||||
------------------------
|
||||
|
||||
There are also a number of examples scripts that showcase Rhai's features, all in the `scripts` directory:
|
||||
|
||||
| Script | Description |
|
||||
| ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
|
||||
| [`array.rhai`]({{repoHome}}/scripts/array.rhai) | [arrays] example |
|
||||
| [`assignment.rhai`]({{repoHome}}/scripts/assignment.rhai) | [variable] declarations |
|
||||
| [`comments.rhai`]({{repoHome}}/scripts/comments.rhai) | just regular [comments] |
|
||||
| [`doc-comments.rhai`]({{repoHome}}/scripts/doc-comments.rhai) | [doc-comments] example |
|
||||
| [`for1.rhai`]({{repoHome}}/scripts/for1.rhai) | [`for`] loops |
|
||||
| [`for2.rhai`]({{repoHome}}/scripts/for2.rhai) | [`for`] loops with [array] iterations |
|
||||
| [`for3.rhai`]({{repoHome}}/scripts/for3.rhai) | [`for`] loops with [closures] |
|
||||
| [`function_decl1.rhai`]({{repoHome}}/scripts/function_decl1.rhai) | a [function] without parameters |
|
||||
| [`function_decl2.rhai`]({{repoHome}}/scripts/function_decl2.rhai) | a [function] with two parameters |
|
||||
| [`function_decl3.rhai`]({{repoHome}}/scripts/function_decl3.rhai) | a [function] with many parameters |
|
||||
| [`function_decl4.rhai`]({{repoHome}}/scripts/function_decl4.rhai) | a [function] acting as a [method]({{rootUrl}}/language/fn-method.md) |
|
||||
| [`function_decl5.rhai`]({{repoHome}}/scripts/function_decl5.rhai) | multiple [functions] as [methods]({{rootUrl}}/language/fn-method.md) for different data types |
|
||||
| [`if1.rhai`]({{repoHome}}/scripts/if1.rhai) | [`if`] example |
|
||||
| [`if2.rhai`]({{repoHome}}/scripts/if2.rhai) | [`if`]-expression example |
|
||||
| [`loop.rhai`]({{repoHome}}/scripts/loop.rhai) | count-down [`loop`] in Rhai, emulating a [`do`] ... `while` loop |
|
||||
| [`module.rhai`]({{repoHome}}/scripts/module.rhai) | import a script file as a module |
|
||||
| [`oop.rhai`]({{repoHome}}/scripts/oop.rhai) | simulate [object-oriented programming (OOP)][OOP] with [closures] |
|
||||
| [`op1.rhai`]({{repoHome}}/scripts/op1.rhai) | just simple addition |
|
||||
| [`op2.rhai`]({{repoHome}}/scripts/op2.rhai) | simple addition and multiplication |
|
||||
| [`op3.rhai`]({{repoHome}}/scripts/op3.rhai) | change evaluation order with parenthesis |
|
||||
| [`string.rhai`]({{repoHome}}/scripts/string.rhai) | [string] operations, including _interpolation_ |
|
||||
| [`strings_map.rhai`]({{repoHome}}/scripts/strings_map.rhai) | [string] and [object map] operations |
|
||||
| [`switch.rhai`]({{repoHome}}/scripts/switch.rhai) | [`switch`] example |
|
||||
| [`while.rhai`]({{repoHome}}/scripts/while.rhai) | [`while`] loop |
|
||||
|
||||
|
||||
Benchmark Scripts
|
||||
-----------------
|
||||
|
||||
The following scripts are for benchmarking the speed of Rhai:
|
||||
|
||||
| Scripts | Description |
|
||||
| --------------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
||||
| [`speed_test.rhai`]({{repoHome}}/scripts/speed_test.rhai) | a simple application to measure the speed of Rhai's interpreter (1 million iterations) |
|
||||
| [`primes.rhai`]({{repoHome}}/scripts/primes.rhai) | use Sieve of Eratosthenes to find all primes smaller than a limit |
|
||||
| [`fibonacci.rhai`]({{repoHome}}/scripts/fibonacci.rhai) | calculate the n-th Fibonacci number using a really dumb algorithm |
|
||||
| [`mat_mul.rhai`]({{repoHome}}/scripts/mat_mul.rhai) | matrix multiplication test to measure the speed of multi-dimensional array access |
|
||||
|
||||
|
||||
Run Example Scripts
|
||||
-------------------
|
||||
|
||||
The [`rhai-run`]({{rootUrl}}/bin.md) utility can be used to run Rhai scripts:
|
||||
|
||||
```sh
|
||||
cargo run --bin rhai-run scripts/any_script.rhai
|
||||
```
|
134
rhai_engine/rhaibook/start/features.md
Normal file
134
rhai_engine/rhaibook/start/features.md
Normal file
@@ -0,0 +1,134 @@
|
||||
Optional Features
|
||||
=================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
By default, Rhai includes all the standard functionalities in a small, tight package.
|
||||
|
||||
```admonish warning "Features are not additive"
|
||||
|
||||
Most Rhai features are not strictly _additive_, i.e. they do not only add optional functionalities.
|
||||
|
||||
In fact, most features are _subtractive_, i.e. they opt-**out** of unneeded functionalities.
|
||||
Notice that this deviates from Rust norm where features are _additive_.
|
||||
|
||||
Excluding functionalities result in smaller, faster builds as well as more control over
|
||||
what scripts can (or cannot) do.
|
||||
|
||||
There is a reason for this design, because the _lack_ of a language feature by itself is a feature (that's deep...).
|
||||
|
||||
See [here]({{rootUrl}}/patterns/multiple.md) for more details.
|
||||
```
|
||||
|
||||
|
||||
Features that Enable Special Functionalities
|
||||
--------------------------------------------
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| ------------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `std` | **no** | standard features |
|
||||
| `sync` | **no** | restricts all values types to those that are `Send + Sync`; under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync` |
|
||||
| `decimal` | **no** | enables the [`Decimal`][rust_decimal] number type (pulls in the [`rust_decimal`][rust_decimal] crate) |
|
||||
| `unicode-xid-ident` | **no** | allows [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) as identifiers (pulls in the [`unicode-xid`](https://crates.io/crates/unicode-xid) crate) |
|
||||
| `serde` | yes | enables serialization/deserialization via `serde` (pulls in the [`serde`](https://crates.io/crates/serde) crate) |
|
||||
| `metadata` | yes | enables exporting [functions metadata]; implies `serde` and additionally pulls in [`serde_json`](https://crates.io/crates/serde_json) |
|
||||
| `internals` | yes | exposes internal data structures (e.g. [`AST`] nodes);<br/><br/>**Safety Warnings**<ul><li>allowing access to internal types may enable external attack vectors</li><li>internal types and functions are volatile and may change from version to version</li></ul> |
|
||||
| `debugging` | yes | enables the [debugging][debugger] interface; implies `internals` |
|
||||
|
||||
|
||||
Features that Disable Certain Language Features
|
||||
-----------------------------------------------
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| ------------------ | :-------: | --------------------------------------------------------- |
|
||||
| `no_float` | **no** | disables floating-point numbers and math |
|
||||
| `no_index` | **no** | disables [arrays] and indexing features |
|
||||
| `no_object` | **no** | disables support for [custom types] and [object maps] |
|
||||
| `no_time` | **no** | disables [timestamps] |
|
||||
| `no_function` | **no** | disables script-defined [functions]; implies `no_closure` |
|
||||
| `no_module` | **no** | disables loading external [modules] |
|
||||
| `no_closure` | **no** | disables capturing external variables in [closures] |
|
||||
| `no_custom_syntax` | **no** | disables [custom syntax] and [custom operators] |
|
||||
|
||||
|
||||
Features that Disable Certain Engine Features
|
||||
---------------------------------------------
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| ------------- | :-------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `unchecked` | **no** | disables [arithmetic checking][checked] (such as over-flows and division by zero), [call stack depth limit][maximum call stack depth], [operations count limit][maximum number of operations], [modules loading limit][maximum number of modules] and [data size limit][maximum length of strings].<br/>Beware that a bad script may panic the entire system! |
|
||||
| `no_optimize` | **no** | disables [script optimization] |
|
||||
| `no_position` | **no** | disables position tracking during parsing |
|
||||
|
||||
|
||||
Features that Configure the Engine
|
||||
----------------------------------
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| ----------- | :-------: | --------------------------------------------------------------------------------------------------- |
|
||||
| `f32_float` | **no** | sets the system floating-point type (`FLOAT`) to `f32` instead of `f64`; no effect under `no_float` |
|
||||
| `only_i32` | **no** | sets the system integer type (`INT`) to `i32` and disable all other integer types |
|
||||
| `only_i64` | **no** | sets the system integer type (`INT`) to `i64` and disable all other integer types |
|
||||
|
||||
|
||||
Features for `no-std` Builds
|
||||
----------------------------
|
||||
|
||||
The following features are provided exclusively for [`no-std`] targets.
|
||||
Do not use them when not compiling for [`no-std`].
|
||||
|
||||
Specify `default-features = false` when compiling for [`no-std`], which will remove the default
|
||||
`std` feature.
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| -------- | :-------: | -------------------------------------------------------------------------------------------------------------- |
|
||||
| `no_std` | **no** | builds for [`no-std`]; notice that additional dependencies will be pulled in to replace missing `std` features |
|
||||
|
||||
|
||||
Features for WebAssembly (WASM) Builds
|
||||
--------------------------------------
|
||||
|
||||
The following features are provided exclusively for [WASM] targets.
|
||||
Do not use them for non-[WASM] targets.
|
||||
|
||||
| Feature | Additive? | Description |
|
||||
| -------------- | :-------: | ---------------------------------------------------------------------------------- |
|
||||
| `wasm-bindgen` | **no** | uses [`wasm-bindgen`](https://crates.io/crates/wasm-bindgen) to compile for [WASM] |
|
||||
| `stdweb` | **no** | uses [`stdweb`](https://crates.io/crates/stdweb) to compile for [WASM] |
|
||||
|
||||
|
||||
Features for Building Bin Tools
|
||||
-------------------------------
|
||||
|
||||
The feature `bin-features` include all the features necessary for building the [bin tools](bin.md).
|
||||
|
||||
By default, it includes: `decimal`, `metadata`, `serde`, `debugging` and `rustyline`.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
The `Cargo.toml` configuration below:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] }
|
||||
```
|
||||
|
||||
turns on these six features:
|
||||
|
||||
| Feature | Description |
|
||||
| :-----------: | ------------------------------------------------------------------------------------ |
|
||||
| `sync` | everything is `Send + Sync` |
|
||||
| `unchecked` | disable all [safety checks][safety] (should not be used with untrusted user scripts) |
|
||||
| `only_i32` | use only 32-bit signed integers and no others |
|
||||
| `no_float` | no floating point numbers |
|
||||
| `no_module` | no loading external [modules] |
|
||||
| `no_function` | no defining [functions] |
|
||||
|
||||
The resulting scripting engine supports only the `i32` integer numeral type (and no others like
|
||||
`u32`, `i16` or `i64`), no floating-point, is `Send + Sync` (so it can be safely used across
|
||||
threads), and does not support defining [functions] nor loading external [modules].
|
||||
|
||||
This configuration is perfect for an expression parser in a 32-bit embedded system without
|
||||
floating-point hardware.
|
6
rhai_engine/rhaibook/start/index.md
Normal file
6
rhai_engine/rhaibook/start/index.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Getting Started
|
||||
===============
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
This section shows how to install the Rhai crate into a Rust application.
|
40
rhai_engine/rhaibook/start/install.md
Normal file
40
rhai_engine/rhaibook/start/install.md
Normal file
@@ -0,0 +1,40 @@
|
||||
Install the Rhai Crate
|
||||
======================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
In order to use Rhai in a project, the Rhai crate must first be made a dependency.
|
||||
|
||||
|
||||
~~~admonish info "Use specific version"
|
||||
|
||||
The easiest way is to install the Rhai crate from [`crates.io`](https://crates.io/crates/rhai/),
|
||||
starting by looking up the latest version and adding this line under `dependencies` in the project's `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = "{{version}}" # assuming {{version}} is the latest version
|
||||
```
|
||||
~~~
|
||||
|
||||
~~~admonish note "Use latest release version"
|
||||
|
||||
Automatically use the latest released crate version on [`crates.io`](https://crates.io/crates/rhai/):
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = "*"
|
||||
```
|
||||
~~~
|
||||
|
||||
~~~admonish tip "Use latest development version"
|
||||
|
||||
Crate versions are released on [`crates.io`](https://crates.io/crates/rhai/) infrequently,
|
||||
so to track the latest features, enhancements and bug fixes, pull directly from
|
||||
[GitHub](https://github.com/rhaiscript/rhai):
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rhai = { git = "https://github.com/rhaiscript/rhai" }
|
||||
```
|
||||
~~~
|
19
rhai_engine/rhaibook/start/playground.md
Normal file
19
rhai_engine/rhaibook/start/playground.md
Normal file
@@ -0,0 +1,19 @@
|
||||
Online Playground
|
||||
=================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
```admonish info.side "See also"
|
||||
|
||||
For more details, see the section [here]({{rootUrl}}/tools/playground.md).
|
||||
```
|
||||
|
||||
Rhai provides an [online playground][playground] to try out its language and engine features without
|
||||
having to install anything.
|
||||
|
||||
The playground provides a syntax-highlighting script editor with example snippets.
|
||||
|
||||
Scripts can be evaluated directly from the editor.
|
||||
|
||||
|
||||
[][playground]
|
Reference in New Issue
Block a user