Edit documentation.

This commit is contained in:
Stephen Chung 2020-06-22 00:03:45 +08:00
parent 7cc1a3f5dc
commit d728ac6758
37 changed files with 386 additions and 147 deletions

View File

@ -42,4 +42,4 @@ Features
Documentation
-------------
See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai script engine and language.
See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai scripting engine and language.

View File

@ -9,12 +9,12 @@ The Rhai Scripting Language
2. [Getting Started](start.md)
1. [Install the Rhai Crate](start/install.md)
2. [Optional Features](start/features.md)
3. [Special Builds](start/builds.md)
1. [Performance Build](start/builds/performance.md)
2. [Minimal Build](start/builds/minimal.md)
3. [no-std Build](start/builds/no-std.md)
3. [Special Builds](start/builds/index.md)
1. [Performance](start/builds/performance.md)
2. [Minimal](start/builds/minimal.md)
3. [no-std](start/builds/no-std.md)
4. [WebAssembly (WASM)](start/builds/wasm.md)
4. [Examples](start/examples.md)
4. [Examples](start/examples/index.md)
1. [Rust](start/examples/rust.md)
2. [Scripts](start/examples/scripts.md)
3. [Using the `Engine`](engine.md)
@ -30,7 +30,7 @@ The Rhai Scripting Language
1. [String Parameters in Rust Functions](rust/strings.md)
3. [Register a Generic Rust Function](rust/generic.md)
4. [Register a Fallible Rust Function](rust/fallible.md)
5. [Packages](rust/packages.md)
5. [Packages](rust/packages/index.md)
1. [Built-in Packages](rust/packages/builtin.md)
2. [Create a Custom Package](rust/packages/create.md)
6. [Override a Built-in Function](rust/override.md)
@ -72,14 +72,14 @@ The Rhai Scripting Language
1. [Function Overloading](language/overload.md)
2. [Call Method as Function](language/method.md)
15. [Print and Debug](language/print-debug.md)
16. [Modules](language/modules.md)
16. [Modules](language/modules/index.md)
1. [Export Variables, Functions and Sub-Modules](language/modules/export.md)
2. [Import Modules](language/modules/import.md)
3. [Create from Rust](language/modules/rust.md)
4. [Create from AST](language/modules/ast.md)
5. [Module Resolvers](language/modules/resolvers.md)
1. [Implement a Custom Module Resolver](language/modules/imp-resolver.md)
6. [Safety and Protection](safety.md)
6. [Safety and Protection](safety/index.md)
1. [Checked Arithmetic](safety/checked.md)
2. [Sand-Boxing](safety/sandbox.md)
3. [Maximum Length of Strings](safety/max-string-size.md)
@ -91,7 +91,7 @@ The Rhai Scripting Language
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
7. [Advanced Topics](advanced.md)
1. [Script Optimization](engine/optimize.md)
1. [Script Optimization](engine/optimize/index.md)
1. [Optimization Levels](engine/optimize/optimize-levels.md)
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
3. [Eager Function Evaluation](engine/optimize/eager.md)
@ -99,3 +99,7 @@ The Rhai Scripting Language
5. [Volatility Considerations](engine/optimize/volatility.md)
6. [Subtle Semantic Changes](engine/optimize/semantics.md)
2. [Eval Statement](language/eval.md)
8. [Appendix](appendix/index.md)
1. [Keywords](appendix/keywords.md)
2. [Operators](appendix/operators.md)
3. [Literals](appendix/literals.md)

View File

@ -5,8 +5,11 @@ Related Resources
Other online documentation resources for Rhai:
* [`DOCS.RS`](https://docs.rs/rhai)
* [`crates.io`](https://crates.io/crates/rhai/) - Rhai crate
* [`DOCS.RS`](https://docs.rs/rhai) - Rhai API documentation
* [`LIB.RS`](https://lib.rs/crates/rhai) - Rhai library info
Other cool projects to check out:

View File

@ -7,4 +7,4 @@ This section covers advanced features such as:
* [Script optimization]
* The dreaded (or beloved depending on your taste) [`eval`] statement
* The dreaded (or beloved for those with twisted tastes) [`eval`] statement

View File

@ -0,0 +1,6 @@
Appendix
========
{{#include ../links.md}}
This section contains miscellaneous reference materials.

View File

@ -0,0 +1,30 @@
Keywords List
=============
{{#include ../links.md}}
| Keyword | Description |
| :--------: | ------------------------------------- |
| `true` | Boolean true literal |
| `false` | Boolean false literal |
| `let` | Variable declaration |
| `const` | Constant declaration |
| `if` | If statement |
| `else` | else block of if statement |
| `while` | While loop |
| `loop` | Infinite loop |
| `for` | For loop |
| `in` | Containment test, part of for loop |
| `continue` | Continue a loop at the next iteration |
| `break` | Loop breaking |
| `return` | Return value |
| `throw` | Throw exception |
| `private` | Mark function private |
| `import` | Import module |
| `export` | Export variable |
| `as` | Alias for variable export |
| `fn` | Function definition |
| `type_of` | Get type name of value |
| `print` | Print value |
| `debug` | Print value in debug format |
| `eval` | Evaluate script |

View File

@ -0,0 +1,16 @@
Literals Syntax
===============
{{#include ../links.md}}
| Type | Literal syntax |
| :--------------------------------: | :---------------------------------------: |
| `INT` | `42`, `-123`, `0` |
| `FLOAT` | `42.0`, `-123.456`, `0.0` |
| [String] | `"... \x?? \u???? \U???????? ..."` |
| Character | `"... \x?? \u???? \U???????? ..."` |
| [`Array`] | `[ ???, ???, ??? ]` |
| [Object map] | `#{ a: ???, b: ???, c: ???, "def": ??? }` |
| Boolean true | `true` |
| Boolean false | `false` |
| `Nothing`/`null`/`nil`/`void`/Unit | `()` |

View File

@ -0,0 +1,30 @@
Operators
=========
{{#include ../links.md}}
| Operator | Description | Binary? |
| :---------------: | ---------------------------- | :-----: |
| `+` | Add | Yes |
| `-` | Subtract, Minus | Yes/No |
| `*` | Multiply | Yes |
| `/` | Divide | Yes |
| `%` | Modulo | Yes |
| `~` | Power | Yes |
| `>>` | Right bit-shift | Yes |
| `<<` | Left bit-shift | Yes |
| `&` | Bit-wise AND, Boolean AND | Yes |
| <code>\|</code> | Bit-wise OR, Boolean OR | Yes |
| `^` | Bit-wise XOR | Yes |
| `==` | Equals to | Yes |
| `~=` | Not equals to | Yes |
| `>` | Greater than | Yes |
| `>=` | Greater than or equals to | Yes |
| `<` | Less than | Yes |
| `<=` | Less than or equals to | Yes |
| `>=` | Greater than or equals to | Yes |
| `&&` | Boolean AND (short-circuits) | Yes |
| <code>\|\|</code> | Boolean OR (short-circuits) | Yes |
| `~` | Boolean NOT | No |
| `[` .. `]` | Indexing | Yes |
| `.` | Property access, Method call | Yes |

View File

@ -1,4 +1,5 @@
{
"version": "0.15.1",
"rootUrl": "",
"rootUrlX": "/rhai"
}

View File

@ -1,7 +1,7 @@
Script Optimization
===================
{{#include ../links.md}}
{{#include ../../links.md}}
Rhai includes an _optimizer_ that tries to optimize a script after parsing.
This can reduce resource utilization and increase execution speed.

View File

@ -3,10 +3,7 @@ Optimization Levels
{{#include ../../links.md}}
Set Optimization Level
---------------------
There are actually three levels of optimizations: `None`, `Simple` and `Full`.
There are three levels of optimization: `None`, `Simple` and `Full`.
* `None` is obvious - no optimization on the AST is performed.
@ -16,6 +13,10 @@ There are actually three levels of optimizations: `None`, `Simple` and `Full`.
* `Full` is _much_ more aggressive, _including_ running functions on constant arguments to determine their result.
One benefit to this is that many more optimization opportunities arise, especially with regards to comparison operators.
Set Optimization Level
---------------------
An [`Engine`]'s optimization level is set via a call to `Engine::set_optimization_level`:
```rust

View File

@ -3,15 +3,38 @@ Re-Optimize an AST
{{#include ../../links.md}}
If it is ever needed to _re_-optimize an `AST`, use the `optimize_ast` method:
Sometimes it is more efficient to store one single, large script with delimited code blocks guarded by
constant variables. This script is compiled once to an `AST`.
Then, depending on the execution environment, constants are passed into the [`Engine`] and the `AST`
is _re_-optimized based on those constants via the `Engine::optimize_ast` method,
effectively pruning out unused code sections.
The final, optimized `AST` is then used for evaluations.
```rust
// Compile script to AST
let ast = engine.compile("40 + 2")?;
// Compile master script to AST
let master_ast = engine.compile(
r"
if SCENARIO_1 {
do_work();
} else if SCENARIO_2 {
do_something();
} else if SCENARIO_3 {
do_something_else();
} else {
do_nothing();
}
")?;
// Create a new 'Scope' - put constants in it to aid optimization if using 'OptimizationLevel::Full'
let scope = Scope::new();
// Create a new 'Scope' - put constants in it to aid optimization
let mut scope = Scope::new();
scope.push_constant("SCENARIO_1", true);
scope.push_constant("SCENARIO_2", false);
scope.push_constant("SCENARIO_3", false);
// Re-optimize the AST
let ast = engine.optimize_ast(&scope, &ast, OptimizationLevel::Full);
let new_ast = engine.optimize_ast(&scope, master_ast.clone(), OptimizationLevel::Simple);
// 'new_ast' is essentially: 'do_work()'
```

View File

@ -13,7 +13,8 @@ print(x * 2); // prints 84
x = 123; // <- syntax error: cannot assign to constant
```
Constants must be assigned a _value_, not an expression.
Unlike variables which need not have initial values (default to [`()`]),
constants must be assigned one, and it must be a constant _value_, not an expression.
```rust
const x = 40 + 2; // <- syntax error: cannot assign expression to constant

View File

@ -6,7 +6,7 @@
Or "How to Shoot Yourself in the Foot even Easier"
------------------------------------------------
Saving the best for last: in addition to script optimizations, there is the ever-dreaded... `eval` function!
Saving the best for last, there is the ever-dreaded... `eval` function!
```rust
let x = 10;

View File

@ -5,6 +5,9 @@
Iterating through a range or an [array] is provided by the `for` ... `in` loop.
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
`break` can be used to break out of the loop unconditionally.
```rust
// Iterate through string, yielding characters
let s = "hello, world!";
@ -41,14 +44,14 @@ for x in range(0, 50, 3) { // step by 3
// Iterate through object map
let map = #{a:1, b:3, c:5, d:7, e:9};
// Property names are returned in random order
// Property names are returned in unsorted, random order
for x in keys(map) {
if x > 10 { continue; } // skip to the next iteration
print(x);
if x == 42 { break; } // break out of for loop
}
// Property values are returned in random order
// Property values are returned in unsorted, random order
for val in values(map) {
print(val);
}

View File

@ -18,6 +18,7 @@ print(add(2, 3)); // prints 5
print(sub(2, 3,)); // prints -1 - trailing comma in arguments list is OK
```
Implicit Return
---------------
@ -38,6 +39,7 @@ print(add(2, 3)); // prints 5
print(add2(42)); // prints 44
```
No Access to External Scope
--------------------------
@ -50,13 +52,15 @@ let x = 42;
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
```
Passing Arguments by Value
-------------------------
Arguments Passed by Value
------------------------
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
It is important to remember that all arguments are passed by _value_, so all functions are _pure_
(i.e. they never modify their arguments).
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).
Any update to an argument will **not** be reflected back to the caller.
This can introduce subtle bugs, if not careful, especially when using the _method-call_ style.
@ -71,6 +75,7 @@ x.change(); // de-sugars to 'change(x)'
x == 500; // 'x' is NOT changed!
```
Global Definitions Only
----------------------
@ -92,6 +97,12 @@ fn do_addition(x) {
}
```
Unlike C/C++, functions can be defined _anywhere_ within the 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.
Use Before Definition
--------------------
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 JS's `function` keyword.

View File

@ -3,24 +3,30 @@
{{#include ../links.md}}
`if` statements follow C syntax:
```rust
if foo(x) {
print("It's true!");
} else if bar == baz {
print("It's true again!");
} else if ... {
:
} else if ... {
:
} else if baz.is_foo() {
print("Yet again true.");
} else if foo(bar - baz) {
print("True again... this is getting boring.");
} else {
print("It's finally false!");
}
```
All branches of an `if` statement must be enclosed within braces '`{`' .. '`}`', even when there is only one statement.
Like Rust, there is no ambiguity regarding which `if` clause a statement belongs to.
Unlike C, the condition expression does _not_ need to be enclosed in parentheses '`(`' .. '`)`', but
all branches of the `if` statement must be enclosed within braces '`{`' .. '`}`',
even when there is only one statement inside the branch.
Like Rust, there is no ambiguity regarding which `if` clause a branch belongs to.
```rust
// Rhai is not C!
if (decision) print("I've decided!");
// ^ syntax error, expecting '{' in statement block
```

View File

@ -3,6 +3,11 @@ Infinite `loop`
{{#include ../links.md}}
Infinite loops follow C syntax.
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
`break` can be used to break out of the loop unconditionally.
```rust
let x = 10;
@ -13,3 +18,6 @@ loop {
if x == 0 { break; } // break out of loop
}
```
Beware: a `loop` statement without a `break` statement inside its loop block is infinite -
there is no way for the loop to stop iterating.

View File

@ -3,11 +3,16 @@ Call Method as Function
{{#include ../links.md}}
Properties and methods in a Rust custom type registered with the [`Engine`] can be called just like a regular function in Rust.
Property getters/setters and methods in a Rust custom type registered with the [`Engine`] can be called
just like a regular function. In fact, like Rust, property getters/setters and object methods
are registered as regular functions in Rhai that take a first `&mut` parameter.
Unlike functions defined in script (for which all arguments are passed by _value_),
native Rust functions may mutate the object (or the first argument if called in normal function call style).
However, sometimes it is not as straight-forward, and methods called in function-call style may end up
not muting the object - see the example below. Therefore, it is best to always use method-call style.
Custom types, properties and methods can be disabled via the [`no_object`] feature.
```rust
@ -21,8 +26,8 @@ update(a); // <- this de-sugars to 'a.update()' thus if 'a' is a simple
let array = [ a ];
update(array[0]); // <- 'array[0]' is an expression returning a calculated value,
// a transient (i.e. a copy) so this statement has no effect
// a transient (i.e. a copy), so this statement has no effect
// except waste a lot of time cloning
array[0].update(); // <- call this method-call style will update 'a'
array[0].update(); // <- call in method-call style will update 'a'
```

View File

@ -1,18 +1 @@
Modules
=======
{{#include ../links.md}}
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
Modules can be disabled via the [`no_module`] feature.
A module is of the type `Module` and encapsulates a Rhai script together with the functions defined
by that script.
The script text is run, variables are then selectively exposed via the [`export`] statement.
Functions defined by the script are automatically exported.
Modules loaded within this module at the global level become _sub-modules_ and are also automatically exported.
Other scripts can then load this module and use the variables and functions exported
as if they were defined inside the same script.
# Modules

View File

@ -7,8 +7,8 @@ For many applications in which Rhai is embedded, it is necessary to customize th
are resolved. For instance, modules may need to be loaded from script texts stored in a database,
not in the file system.
A module resolver must implement the trait `rhai::ModuleResolver`, which contains only one function:
`resolve`.
A module resolver must implement the trait [`rhai::ModuleResolver`]({{rootUrl}}/rust/traits.md),
which contains only one function: `resolve`.
When Rhai prepares to load a module, `ModuleResolver::resolve` is called with the name
of the _module path_ (i.e. the path specified in the [`import`] statement). Upon success, it should

View File

@ -3,6 +3,9 @@ Import a Module
{{#include ../../links.md}}
`import` Statement
-----------------
A module can be _imported_ via the `import` statement, and its members are accessed via '`::`' similar to C++.
```rust
@ -17,10 +20,14 @@ print(lock::status); // module variables are constants
lock::status = "off"; // <- runtime error - cannot modify a constant
```
Scoped Imports
--------------
`import` statements are _scoped_, meaning that they are only accessible inside the scope that they're imported.
They can appear anywhere a normal statement can be, but in the vast majority of cases `import` statements are
group at the beginning of a script. It is, however, not advised to deviate from this common practice unless
group at the beginning of a script. It is not advised to deviate from this common practice unless
there is a _Very Good Reason™_.
Especially, do not place an `import` statement within a loop; doing so will repeatedly re-load the same module
@ -44,3 +51,32 @@ for x in range(0, 1000) {
c.encrypt(something);
}
```
Recursive Imports
----------------
Beware of _import cycles_ - i.e. recursively loading the same module. This is a sure-fire way to
cause a stack overflow in the [`Engine`], unless stopped by setting a limit for [maximum number of modules].
For instance, importing itself always causes an infinite recursion:
```rust
// This file is 'hello.rhai'
import "hello" as foo; // import itself - infinite recursion!
foo::do_something();
```
Modules cross-referencing also cause infinite recursion:
```rust
// This file is 'hello.rhai' - references 'world.rhai'
import "world" as foo;
foo::do_something();
// This file is 'world.rhai' - references 'hello.rhai'
import "hello" as bar;
bar::do_something_else();
```

View File

@ -0,0 +1,18 @@
Modules
=======
{{#include ../../links.md}}
Rhai allows organizing code (functions, both Rust-based or script-based, and variables) into _modules_.
Modules can be disabled via the [`no_module`] feature.
A module is of the type `Module` and encapsulates a Rhai script together with the functions defined
by that script.
The script text is run, variables are then selectively exposed via the [`export`] statement.
Functions defined by the script are automatically exported.
Modules loaded within this module at the global level become _sub-modules_ and are also automatically exported.
Other scripts can then load this module and use the variables and functions exported
as if they were defined inside the same script.

View File

@ -3,8 +3,14 @@ Return Values
{{#include ../links.md}}
The `return` statement is used to immediately stop evaluation and exist the current context
(typically a function call) yielding a _return value_.
```rust
return; // equivalent to return ();
return 123 + 456; // returns 579
```
A `return` statement at _global_ level stop the entire script evaluation,
the return value is taken as the result of the script evaluation.

View File

@ -3,13 +3,14 @@ Statements
{{#include ../links.md}}
Terminated by '`;`'
------------------
Statements are terminated by semicolons '`;`' and they are mandatory,
except for the _last_ statement in a _block_ (enclosed by '`{`' .. '`}`' pairs) where it can be omitted.
A statement can be used anywhere where an expression is expected. These are called, for lack of a more
creative name, "statement expressions." The _last_ statement of a statement block is _always_ the block's
return value when used as a statement.
If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`].
Semicolons can also be omitted if the statement contains a block itself
(e.g. the `if`, `while`, `for` and `loop` statements).
```rust
let a = 42; // normal assignment statement
@ -20,6 +21,20 @@ let a = { 40 + 2 }; // 'a' is set to the value of the statement block, which
// ^ the last statement does not require a terminating semicolon (although it also works with it)
// ^ semicolon required here to terminate the assignment statement; it is a syntax error without it
4 * 10 + 2 // a statement which is just one expression; no ending semicolon is OK
if foo { a = 42 }
// ^ there is no need to terminate an if-statement with a semicolon
4 * 10 + 2 // a statement which is just one expression - no ending semicolon is OK
// because it is the last statement of the whole block
```
Statement Expression
--------------------
A statement can be used anywhere where an expression is expected. These are called, for lack of a more
creative name, "statement expressions."
The _last_ statement of a statement block is _always_ the block's return value when used as a statement.
If the last statement has no return value (e.g. variable definitions, assignments) then it is assumed to be [`()`].

View File

@ -3,6 +3,9 @@ Variables
{{#include ../links.md}}
Valid Names
-----------
Variables in Rhai follow normal C naming rules (i.e. must contain only ASCII letters, digits and underscores '`_`').
Variable names must start with an ASCII letter or an underscore '`_`', must contain at least one ASCII letter,
@ -11,9 +14,21 @@ and must start with an ASCII letter before a digit.
Therefore, names like '`_`', '`_42`', '`3a`' etc. are not legal variable names, but '`_c3po`' and '`r2d2`' are.
Variable names are also case _sensitive_.
Variables are defined using the `let` keyword. A variable defined within a statement block is _local_ to that block.
Variable names cannot be the same as a [keyword].
Declare a Variable
------------------
Variables are declared using the `let` keyword.
Variables do not have to be given an initial value.
If none is provided, then it defaults to [`()`].
A variable defined within a statement block is _local_ to that block.
```rust
let x; // ok - value is '()'
let x = 3; // ok
let _x = 42; // ok
let x_ = 42; // also ok

View File

@ -3,6 +3,11 @@
{{#include ../links.md}}
`while` loops follow C syntax.
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
`break` can be used to break out of the loop unconditionally.
```rust
let x = 10;

View File

@ -23,8 +23,8 @@
[`eval_expression_with_scope`]: {{rootUrl}}/engine/expressions.md
[raw `Engine`]: {{rootUrl}}/engine/raw.md
[built-in operators]: {{rootUrl}}/engine/raw.md#built-in-operators
[package]: {{rootUrl}}/rust/packages.md
[packages]: {{rootUrl}}/rust/packages.md
[package]: {{rootUrl}}/rust/packages/index.md
[packages]: {{rootUrl}}/rust/packages/index.md
[`Scope`]: {{rootUrl}}/rust/scope.md
[`type_of()`]: {{rootUrl}}/language/type-of.md
@ -41,6 +41,9 @@
[`print`]: {{rootUrl}}/language/print-debug.md
[`debug`]: {{rootUrl}}/language/print-debug.md
[keywords]: {{rootUrl}}/appendix/keywords.md
[keyword]: {{rootUrl}}/appendix/keywords.md
[variable]: {{rootUrl}}/language/variables.md
[variables]: {{rootUrl}}/language/variables.md
@ -63,9 +66,9 @@
[function]: {{rootUrl}}/language/functions.md
[functions]: {{rootUrl}}/language/functions.md
[`Module`]: {{rootUrl}}/language/modules.md
[module]: {{rootUrl}}/language/modules.md
[modules]: {{rootUrl}}/language/modules.md
[`Module`]: {{rootUrl}}/language/modules/index.md
[module]: {{rootUrl}}/language/modules/index.md
[modules]: {{rootUrl}}/language/modules/index.md
[`export`]: {{rootUrl}}/language/modules/export.md
[`import`]: {{rootUrl}}/language/modules/import.md
@ -80,7 +83,7 @@
[maximum size of object maps]: {{rootUrl}}/safety/max-map-size.md
[progress]:/safety/progress.md
[script optimization]: {{rootUrl}}/engine/optimize.md
[script optimization]: {{rootUrl}}/engine/optimize/index.md
[`OptimizationLevel::Full`]: {{rootUrl}}/engine/optimize/optimize-levels.md
[`OptimizationLevel::Simple`]: {{rootUrl}}/engine/optimize/optimize-levels.md
[`OptimizationLevel::None`]: {{rootUrl}}/engine/optimize/optimize-levels.md

View File

@ -1,7 +1,7 @@
Packages
========
{{#include ../links.md}}
{{#include ../../links.md}}
Standard built-in Rhai features are provided in various _packages_ that can be loaded via a call to `Engine::load_package`.

View File

@ -1,31 +1 @@
Safety and Protection Against DoS Attacks
========================================
{{#include links.md}}
For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of
resources used by a script so that it does not consume more resources that it is allowed to.
The most important resources to watch out for are:
* **Memory**: A malicous script may continuously grow a [string], an [array] or [object map] until all memory is consumed.
It may also create a large [array] or [object map] literal that exhausts all memory during parsing.
* **CPU**: A malicous script may run an infinite tight loop that consumes all CPU cycles.
* **Time**: A malicous script may run indefinitely, thereby blocking the calling system which is waiting for a result.
* **Stack**: A malicous script may attempt an infinite recursive call that exhausts the call stack.
Alternatively, it may create a degenerated deep expression with so many levels that the parser exhausts the call stack
when parsing the expression; or even deeply-nested statement blocks, if nested deep enough.
* **Overflows**: A malicous script may deliberately cause numeric over-flows and/or under-flows, divide by zero, and/or
create bad floating-point representations, in order to crash the system.
* **Files**: A malicous script may continuously [`import`] an external module within an infinite loop,
thereby putting heavy load on the file-system (or even the network if the file is not local).
Furthermore, the module script may simply [`import`] itself in an infinite recursion.
Even when modules are not created from files, they still typically consume a lot of resources to load.
* **Data**: A malicous script may attempt to read from and/or write to data that it does not own. If this happens,
it is a severe security breach and may put the entire system at risk.
# Safety and Protection

35
doc/src/safety/index.md Normal file
View File

@ -0,0 +1,35 @@
Safety and Protection Against DoS Attacks
========================================
{{#include ../links.md}}
For scripting systems open to untrusted user-land scripts, it is always best to limit the amount of
resources used by a script so that it does not consume more resources that it is allowed to.
The most important resources to watch out for are:
* **Memory**: A malicous script may continuously grow a [string], an [array] or [object map] until all memory is consumed.
It may also create a large [array] or [object map] literal that exhausts all memory during parsing.
* **CPU**: A malicous script may run an infinite tight loop that consumes all CPU cycles.
* **Time**: A malicous script may run indefinitely, thereby blocking the calling system which is waiting for a result.
* **Stack**: A malicous script may attempt an infinite recursive call that exhausts the call stack.
Alternatively, it may create a degenerated deep expression with so many levels that the parser exhausts the call stack
when parsing the expression; or even deeply-nested statement blocks, if nested deep enough.
Another way to cause a stack overflow is to load a [self-referencing module]({{rootUrl}}/language/modules/import.md).
* **Overflows**: A malicous script may deliberately cause numeric over-flows and/or under-flows, divide by zero, and/or
create bad floating-point representations, in order to crash the system.
* **Files**: A malicous script may continuously [`import`] an external module within an infinite loop,
thereby putting heavy load on the file-system (or even the network if the file is not local).
Even when modules are not created from files, they still typically consume a lot of resources to load.
* **Data**: A malicous script may attempt to read from and/or write to data that it does not own. If this happens,
it is a severe security breach and may put the entire system at risk.

View File

@ -10,6 +10,9 @@ of modules to zero does _not_ indicate unlimited modules, but disallows loading
A script attempting to load more than the maximum number of modules will terminate with an error result.
This limit can also be used to stop [`import`-loops]({{rootUrl}}/language/modules/import.md)
(i.e. cycles of modules referring to each other).
This check can be disabled via the [`unchecked`] feature for higher performance
(but higher risks as well).

View File

@ -1,7 +1,7 @@
Special Builds
==============
{{#include ../links.md}}
{{#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.

View File

@ -1,7 +1,7 @@
Examples
========
{{#include ../links.md}}
{{#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.

View File

@ -4,10 +4,12 @@ Optional Features
{{#include ../links.md}}
By default, Rhai includes all the standard functionalities in a small, tight package.
Most features are here to opt-**out** of certain functionalities that are not needed.
Excluding unneeded functionalities can result in smaller, faster builds
as well as more control over what a script can (or cannot) do.
Most features are here to opt-**out** of certain functionalities that are not needed.
Notice that this deviates from Rust norm where features are _additive_.
Excluding unneeded functionalities can result in smaller, faster builds as well as
more control over what a script can (or cannot) do.
| Feature | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
@ -38,7 +40,7 @@ The `Cargo.toml` configuration below turns on these six features:
```toml
[dependencies]
rhai = { version = "0.15.2", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] }
rhai = { version = "{{version}}", features = [ "sync", "unchecked", "only_i32", "no_float", "no_module", "no_function" ] }
```
The resulting scripting engine supports only the `i32` integer numeral type (and no others like `u32` or `i16`),

View File

@ -3,15 +3,15 @@ Install the Rhai Crate
{{#include ../links.md}}
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/) by adding this line
under `dependencies` in `Cargo.toml`:
Install the Rhai crate from [`crates.io`](https:/crates.io/crates/rhai/), start by looking up the
latest version and adding this line under `dependencies` in `Cargo.toml`:
```toml
[dependencies]
rhai = "0.15.2"
rhai = "{{version}}" # assuming {{version}} is the latest version
```
Use the latest released crate version on [`crates.io`](https:/crates.io/crates/rhai/):
Or to automatically use the latest released crate version on [`crates.io`](https:/crates.io/crates/rhai/):
```toml
[dependencies]

View File

@ -44,13 +44,13 @@ fn test_side_effects_command() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
let mut scope = Scope::new();
// Create the command object with initial state, handled by an `Rc`.
// Create the command object with initial state, handled by an `Arc`.
let command = Arc::new(Mutex::new(Command { state: 12 }));
assert_eq!(command.lock().unwrap().get(), 12);
// Create the wrapper.
let wrapper = CommandWrapper {
command: command.clone(), // Notice this clones the `Rc` only
command: command.clone(), // Notice this clones the `Arc` only
};
// Make the wrapper a singleton in the script environment.