Add more comments and examples.

This commit is contained in:
Stephen Chung 2020-03-19 13:52:10 +08:00
parent b3efb8b264
commit cc8ec12691
14 changed files with 633 additions and 245 deletions

247
README.md
View File

@ -13,8 +13,9 @@ Rhai's current features set:
* Easy-to-use language similar to JS+Rust
* Support for overloaded functions
* Compiled script is optimized for repeat evaluations
* Very few additional dependencies (right now only [`num-traits`] to do checked arithmetic operations);
For [`no_std`] builds, a number of additional dependencies are pulled in to provide for basic library functionalities.
* Very few additional dependencies (right now only [`num-traits`](https://crates.io/crates/num-traits/)
to do checked arithmetic operations); for [`no_std`] builds, a number of additional dependencies are
pulled in to provide for functionalities that used to be in `std`.
**Note:** Currently, the version is 0.11.0, so the language and API's may change before they stabilize.
@ -57,6 +58,16 @@ Optional features
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 less bugs due to a more restricted language.
[`unchecked`]: #optional-features
[`no_stdlib`]: #optional-features
[`no_index`]: #optional-features
[`no_float`]: #optional-features
[`no_function`]: #optional-features
[`no_optimize`]: #optional-features
[`only_i32`]: #optional-features
[`only_i64`]: #optional-features
[`no_std`]: #optional-features
Related
-------
@ -126,6 +137,8 @@ cargo run --example rhai_runner scripts/any_script.rhai
Hello world
-----------
[`Engine`]: #hello-world
To get going with Rhai, create an instance of the scripting engine and then call `eval`:
```rust
@ -224,35 +237,62 @@ let result: i64 = engine.call_fn("hello", 123_i64)?
Values and types
----------------
[`type_of`]: #values-and-types
The following primitive types are supported natively:
| Category | Types |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| **Integer** | `u8`, `i8`, `u16`, `i16`, <br/>`u32`, `i32` (default for [`only_i32`]),<br/>`u64`, `i64` _(default)_ |
| **Floating-point** (disabled with [`no_float`]) | `f32`, `f64` _(default)_ |
| **Character** | `char` |
| **Boolean** | `bool` |
| **Array** (disabled with [`no_index`]) | `rhai::Array` |
| **Dynamic** (i.e. can be anything) | `rhai::Dynamic` |
| **System** (current configuration) | `rhai::INT` (`i32` or `i64`),<br/>`rhai::FLOAT` (`f32` or `f64`) |
| Category | Equivalent Rust types | `type_of()` name |
| ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------- |
| **Integer number** | `u8`, `i8`, `u16`, `i16`, <br/>`u32`, `i32` (default for [`only_i32`]),<br/>`u64`, `i64` _(default)_ | _same as type_ |
| **Floating-point number** (disabled with [`no_float`]) | `f32`, `f64` _(default)_ | _same as type_ |
| **Boolean value** | `bool` | `"bool"` |
| **Unicode character** | `char` | `"char"` |
| **Unicode string** | `String` (_not_ `&str`) | `"string"` |
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` |
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ |
| **System number** (current configuration) | `rhai::INT` (`i32` or `i64`),<br/>`rhai::FLOAT` (`f32` or `f64`) | _same as type_ |
| **Nothing/void/nil/null** (or whatever you want to call it) | `()` | `"()"` |
[`Dynamic`]: #values-and-types
[`()`]: #values-and-types
All types are treated strictly separate by Rhai, meaning that `i32` and `i64` and `u32` are completely different - they even cannot be added together. This is very similar to Rust.
The default integer type is `i64`. If other integer types are not needed, it is possible to exclude them and make a smaller build with the [`only_i64`] feature.
If only 32-bit integers are needed, enabling the [`only_i32`] feature will remove support for all integer types other than `i32`, including `i64`.
This is useful on 32-bit systems where using 64-bit integers incur a performance penalty.
This is useful on some 32-bit systems where using 64-bit integers incurs a performance penalty.
If no floating-point is needed, use the [`no_float`] feature to remove support.
If no floating-point is needed or supported, use the [`no_float`] feature to remove it.
There is a `type_of` function to detect the actual type of a value. This is useful because all variables are `Dynamic`.
```rust
// Use 'type_of()' to get the actual types of values
type_of('c') == "char";
type_of(42) == "i64";
let x = 123;
x.type_of() == "i64";
x = 99.999;
x.type_of() == "f64";
x = "hello";
if type_of(x) == "string" {
do_something_with_string(x);
}
```
Value conversions
-----------------
[`to_int`]: #value-conversions
[`to_float`]: #value-conversions
There is a `to_float` function to convert a supported number to an `f64`, and a `to_int` function to convert a supported number to `i64` and that's about it.
For other conversions, register custom conversion functions.
There is also a `type_of` function to detect the type of a value.
```rust
let x = 42;
let y = x * 100.0; // error: cannot multiply i64 with f64
@ -261,22 +301,13 @@ let z = y.to_int() + x; // works
let c = 'X'; // character
print("c is '" + c + "' and its code is " + c.to_int()); // prints "c is 'X' and its code is 88"
// Use 'type_of' to get the type of variables
type_of(c) == "char";
type_of(x) == "i64";
y.type_of() == "f64";
if z.type_of() == "string" {
do_something_with_strong(z);
}
```
Working with functions
----------------------
Rhai's scripting engine is very lightweight. It gets most of its abilities from functions.
To call these functions, they need to be registered with the engine.
To call these functions, they need to be registered with the [`Engine`].
```rust
use rhai::{Engine, EvalAltResult};
@ -314,7 +345,7 @@ fn main() -> Result<(), EvalAltResult>
}
```
To return a [`Dynamic`] value, simply `Box` it and return it.
To return a [`Dynamic`] value from a Rust function, simply `Box` it and return it.
```rust
fn decide(yes_no: bool) -> Dynamic {
@ -412,16 +443,16 @@ use rhai::RegisterFn;
#[derive(Clone)]
struct TestStruct {
x: i64
field: i64
}
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
self.field += 41;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
fn new() -> Self {
TestStruct { field: 1 }
}
}
@ -436,7 +467,7 @@ fn main() -> Result<(), EvalAltResult>
let result = engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")?;
println!("result: {}", result.x); // prints 1001
println!("result: {}", result.field); // prints 42
Ok(())
}
@ -447,7 +478,7 @@ All custom types must implement `Clone`. This allows the [`Engine`] to pass by
```rust
#[derive(Clone)]
struct TestStruct {
x: i64
field: i64
}
```
@ -456,11 +487,11 @@ Next, we create a few methods that we'll later use in our scripts. Notice that
```rust
impl TestStruct {
fn update(&mut self) {
self.x += 1000;
self.field += 41;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
fn new() -> Self {
TestStruct { field: 1 }
}
}
@ -474,8 +505,8 @@ To use methods and functions with the [`Engine`], we need to register them. The
*Note: [`Engine`] follows the convention that methods use a `&mut` first parameter so that invoking methods can update the value in memory.*
```rust
engine.register_fn("update", TestStruct::update);
engine.register_fn("new_ts", TestStruct::new);
engine.register_fn("update", TestStruct::update); // registers 'update(&mut ts)'
engine.register_fn("new_ts", TestStruct::new); // registers 'new'
```
Finally, we call our script. The script can see the function and method we registered earlier. We need to get the result back out from script land just as before, this time casting to our custom struct type.
@ -483,14 +514,14 @@ Finally, we call our script. The script can see the function and method we regi
```rust
let result = engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")?;
println!("result: {}", result.x); // prints 1001
println!("result: {}", result.field); // prints 42
```
In fact, any function with a first argument (either by copy or via a `&mut` reference) can be used as a method-call on that type because internally they are the same thing: methods on a type is implemented as a functions taking an first argument.
```rust
fn foo(ts: &mut TestStruct) -> i64 {
ts.x
ts.field
}
engine.register_fn("foo", foo);
@ -500,14 +531,19 @@ let result = engine.eval::<i64>("let x = new_ts(); x.foo()")?;
println!("result: {}", result); // prints 1
```
`type_of` works fine with custom types and returns the name of the type. If `register_type_with_name` is used to register the custom type
with a special "pretty-print" name, `type_of` will return that name instead.
[`type_of`] works fine with custom types and returns the name of the type. If `register_type_with_name` is used to register the custom type
with a special "pretty-print" name, [`type_of`] will return that name instead.
```rust
engine.register_type::<TestStruct>();
engine.register_fn("new_ts", TestStruct::new);
let x = new_ts();
print(x.type_of()); // prints "foo::bar::TestStruct"
// prints "Hello" if TestStruct is registered with
// engine.register_type_with_name::<TestStruct>("Hello")?;
print(x.type_of()); // prints "path::to::module::TestStruct"
engine.register_type_with_name::<TestStruct>("Hello");
engine.register_fn("new_ts", TestStruct::new);
let x = new_ts();
print(x.type_of()); // prints "Hello"
```
Getters and setters
@ -518,20 +554,20 @@ Similarly, custom types can expose members by registering a `get` and/or `set` f
```rust
#[derive(Clone)]
struct TestStruct {
x: i64
field: i64
}
impl TestStruct {
fn get_x(&mut self) -> i64 {
self.x
fn get_field(&mut self) -> i64 {
self.field
}
fn set_x(&mut self, new_x: i64) {
self.x = new_x;
fn set_field(&mut self, new_val: i64) {
self.field = new_val;
}
fn new() -> TestStruct {
TestStruct { x: 1 }
fn new() -> Self {
TestStruct { field: 1 }
}
}
@ -539,17 +575,19 @@ let mut engine = Engine::new();
engine.register_type::<TestStruct>();
engine.register_get_set("x", TestStruct::get_x, TestStruct::set_x);
engine.register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
engine.register_fn("new_ts", TestStruct::new);
let result = engine.eval::<i64>("let a = new_ts(); a.x = 500; a.x")?;
let result = engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?;
println!("result: {}", result);
println!("Answer: {}", result); // prints 42
```
Initializing and maintaining state
---------------------------------
[`Scope`]: #initializing-and-maintaining-state
By default, Rhai treats each [`Engine`] invocation as a fresh one, persisting only the functions that have been defined but no global state.
This gives each evaluation a clean starting slate. In order to continue using the same global state from one invocation to the next,
such a state must be manually created and passed in.
@ -571,20 +609,21 @@ fn main() -> Result<(), EvalAltResult>
// Better stick to them or it gets hard working with the script.
scope.push("y", 42_i64);
scope.push("z", 999_i64);
scope.push("s", "hello, world!".to_string()); // remember to use 'String', not '&str'
// First invocation
engine.eval_with_scope::<()>(&mut scope, r"
let x = 4 + 5 - y + z;
let x = 4 + 5 - y + z + s.len();
y = 1;
")?;
// Second invocation using the same state
let result = engine.eval_with_scope::<i64>(&mut scope, "x")?;
println!("result: {}", result); // should print 966
println!("result: {}", result); // prints 979
// Variable y is changed in the script
assert_eq!(scope.get_value::<i64>("y")?, 1);
assert_eq!(scope.get_value::<i64>("y").expect("variable x should exist"), 1);
Ok(())
}
@ -620,15 +659,16 @@ Statements are terminated by semicolons '`;`' - they are mandatory, except for t
A statement can be used anywhere where an expression is expected. The _last_ statement of a statement block
(enclosed by '`{`' .. '`}`' pairs) is always the return value of the statement. If a statement has no return value
(e.g. variable definitions, assignments) then the value will be `()`.
(e.g. variable definitions, assignments) then the value will be [`()`].
```rust
let a = 42; // normal assignment statement
let a = foo(42); // normal function call statement
foo < 42; // normal expression as statement
let a = { 40 + 2 }; // the value of 'a' is the value of the statement block, which is the value of the last statement
// ^ notice that the last statement does not require an ending semicolon
let a = { 40 + 2 }; // 'a' is set to the value of the statement block, which is the value of the last statement
// ^ notice that the last statement does not require a terminating semicolon (although it also works with it)
// ^ notice that a semicolon is required here to terminate the assignment statement; it is syntax error without it
4 * 10 + 2 // this is also a statement, which is an expression, with no ending semicolon because
// it is the last statement of the whole block
@ -639,8 +679,9 @@ Variables
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 '`_`', and must contain at least one ASCII letter within.
Therefore, names like '`_`', '`_42`' etc. are not legal variable names. Variable names are also case _sensitive_.
Variable names must start with an ASCII letter or an underscore '`_`', must contain at least one ASCII letter, 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.
@ -676,7 +717,7 @@ print(x * 2); // prints 84
x = 123; // syntax error - cannot assign to constant
```
Constants must be assigned a _value_ not an expression.
Constants must be assigned a _value_, not an expression.
```rust
const x = 40 + 2; // syntax error - cannot assign expression to constant
@ -707,11 +748,11 @@ Numeric operators
Numeric operators generally follow C styles.
| Operator | Description | Integers only |
| -------- | ----------------------------------------------------------- | :-----------: |
| -------- | ---------------------------------------------------- | :-----------: |
| `+` | Plus | |
| `-` | Minus | |
| `*` | Multiply | |
| `/` | Divide (C-style integer division if acted on integer types) | |
| `/` | Divide (integer division if acting on integer types) | |
| `%` | Modulo (remainder) | |
| `~` | Power | |
| `&` | Binary _And_ bit-mask | Yes |
@ -748,9 +789,9 @@ Numeric functions
The following standard functions (defined in the standard library but excluded if [`no_stdlib`]) operate on `i8`, `i16`, `i32`, `i64`, `f32` and `f64` only:
| Function | Description |
| ---------- | --------------------------------- |
| ------------ | --------------------------------- |
| `abs` | absolute value |
| `to_float` | converts an integer type to `f64` |
| [`to_float`] | converts an integer type to `f64` |
Floating-point functions
------------------------
@ -765,7 +806,7 @@ The following standard functions (defined in the standard library but excluded i
| Exponential | `exp` (base _e_) |
| Logarithmic | `ln` (base _e_), `log10` (base 10), `log` (any base) |
| Rounding | `floor`, `ceiling`, `round`, `int`, `fraction` |
| Conversion | `to_int` |
| Conversion | [`to_int`] |
| Testing | `is_nan`, `is_finite`, `is_infinite` |
Strings and Chars
@ -782,7 +823,7 @@ Individual characters within a Rhai string can be replaced. In Rhai, there is no
Strings can be built up from other strings and types via the `+` operator (provided by the standard library but excluded if [`no_stdlib`]).
This is particularly useful when printing output.
`type_of()` a string returns `"string"`.
[`type_of()`] a string returns `"string"`.
```rust
let name = "Bob";
@ -871,7 +912,7 @@ Arrays
Arrays are first-class citizens in Rhai. Like C, arrays are accessed with zero-based, non-negative integer indices.
Array literals are built within square brackets '`[`' ,, '`]`' and separated by commas '`,`'.
The type of a Rhai array is `rhai::Array`. `type_of()` returns `"array"`.
The type of a Rhai array is `rhai::Array`. [`type_of()`] an array returns `"array"`.
Arrays are disabled via the [`no_index`] feature.
@ -880,8 +921,8 @@ The following functions (defined in the standard library but excluded if [`no_st
| Function | Description |
| ---------- | ------------------------------------------------------------------------------------- |
| `push` | inserts an element at the end |
| `pop` | removes the last element and returns it (`()` if empty) |
| `shift` | removes the first element and returns it (`()` if empty) |
| `pop` | removes the last element and returns it ([`()`] if empty) |
| `shift` | removes the first element and returns it ([`()`] if empty) |
| `len` | returns the number of elements |
| `pad` | pads the array with an element until a specified length |
| `clear` | empties the array |
@ -941,9 +982,7 @@ print(y.len()); // prints 0
`push` and `pad` are only defined for standard built-in types. For custom types, type-specific versions must be registered:
```rust
engine.register_fn("push",
|list: &mut Array, item: MyType| list.push(Box::new(item))
);
engine.register_fn("push", |list: &mut Array, item: MyType| list.push(Box::new(item)) );
```
Comparison operators
@ -1103,7 +1142,7 @@ return 123 + 456; // returns 579
Errors and exceptions
---------------------
All of `Engine`'s evaluation/consuming methods return `Result<T, rhai::EvalAltResult>` with `EvalAltResult` holding error information.
All of [`Engine`]'s evaluation/consuming methods return `Result<T, rhai::EvalAltResult>` with `EvalAltResult` holding error information.
To deliberately return an error during an evaluation, use the `throw` keyword.
```rust
@ -1215,11 +1254,11 @@ abc(); // prints "None."
Members and methods
-------------------
Properties and methods in a Rust custom type registered with the engine can be called just like in Rust:
Properties and methods in a Rust custom type registered with the [`Engine`] can be called just like in Rust:
```rust
let a = new_ts(); // constructor function
a.x = 500; // property access
a.field = 500; // property access
a.update(); // method call
```
@ -1307,8 +1346,8 @@ print("done!"); // <- the line above is further simp
These are quite effective for template-based machine-generated scripts where certain constant values
are spliced into the script text in order to turn on/off certain sections.
For fixed script texts, the constant values can be provided in a user-defined `Scope` object
to the `Engine` for use in compilation and evaluation.
For fixed script texts, the constant values can be provided in a user-defined [`Scope`] object
to the [`Engine`] for use in compilation and evaluation.
Beware, however, that most operators are actually function calls, and those functions can be overridden,
so they are not optimized away:
@ -1353,9 +1392,14 @@ large `if`-`else` branches because they do not depend on operators.
Alternatively, turn the optimizer to [`OptimizationLevel::Full`]
Here be dragons!
----------------
================
### Optimization levels
Optimization levels
-------------------
[`OptimizationLevel::Full`]: #optimization-levels
[`OptimizationLevel::Simple`]: #optimization-levels
[`OptimizationLevel::None`]: #optimization-levels
There are actually three levels of optimizations: `None`, `Simple` and `Full`.
@ -1367,14 +1411,14 @@ 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.
An engine's optimization level is set via a call to `set_optimization_level`:
An [`Engine`]'s optimization level is set via a call to `set_optimization_level`:
```rust
// Turn on aggressive optimizations
engine.set_optimization_level(rhai::OptimizationLevel::Full);
```
When the optimization level is [`OptimizationLevel::Full`], the engine assumes all functions to be _pure_ and will _eagerly_
When the optimization level is [`OptimizationLevel::Full`], the [`Engine`] assumes all functions to be _pure_ and will _eagerly_
evaluated all function calls with constant arguments, using the result to replace the call. This also applies to all operators
(which are implemented as functions). For instance, the same example above:
@ -1393,7 +1437,7 @@ print("hello!"); // <- the above is equivalent to this ('print' and 'debu
```
Because of the eager evaluation of functions, many constant expressions will be evaluated and replaced by the result.
This does not happen with `OptimizationLevel::Simple` which doesn't assume all functions to be _pure_.
This does not happen with [`OptimizationLevel::Simple`] which doesn't assume all functions to be _pure_.
```rust
// When compiling the following with OptimizationLevel::Full...
@ -1402,7 +1446,8 @@ let x = (1 + 2) * 3 - 4 / 5 % 6; // <- will be replaced by 'let x = 9'
let y = (1 > 2) || (3 <= 4); // <- will be replaced by 'let y = true'
```
### Function side effect considerations
Function side effect considerations
----------------------------------
All of Rhai's built-in functions (and operators which are implemented as functions) are _pure_ (i.e. they do not mutate state
nor cause side any effects, with the exception of `print` and `debug` which are handled specially) so using [`OptimizationLevel::Full`]
@ -1412,7 +1457,8 @@ If custom functions are registered, they _may_ be called (or maybe not, if the c
If custom functions are registered to replace built-in operators, they will also be called when the operators are used (in an `if`
statement, for example) and cause side-effects.
### Function volatility considerations
Function volatility considerations
---------------------------------
Even if a custom function does not mutate state nor cause side effects, it may still be _volatile_, i.e. it _depends_ on the external
environment and not _pure_. A perfect example is a function that gets the current time - obviously each run will return a different value!
@ -1422,7 +1468,8 @@ always be the same value.
Therefore, **avoid using [`OptimizationLevel::Full`]** if you intend to register non-_pure_ custom types and/or functions.
### Subtle semantic changes
Subtle semantic changes
-----------------------
Some optimizations can alter subtle semantics of the script. For example:
@ -1456,10 +1503,11 @@ In the script above, if `my_decision` holds anything other than a boolean value,
However, after optimization, the entire `if` statement is removed (because an access to `my_decision` produces no side effects),
thus the script silently runs to completion without errors.
### Turning off optimizations
Turning off optimizations
-------------------------
It is usually a bad idea to depend on a script failing or such kind of subtleties, but if it turns out to be necessary (why? I would never guess),
turn it off by setting the optimization level to `OptimizationLevel::None`.
turn it off by setting the optimization level to [`OptimizationLevel::None`].
```rust
let engine = rhai::Engine::new();
@ -1467,22 +1515,3 @@ let engine = rhai::Engine::new();
// Turn off the optimizer
engine.set_optimization_level(rhai::OptimizationLevel::None);
```
[`num-traits`]: https://crates.io/crates/num-traits/
[`debug_msgs`]: #optional-features
[`unchecked`]: #optional-features
[`no_stdlib`]: #optional-features
[`no_index`]: #optional-features
[`no_float`]: #optional-features
[`no_function`]: #optional-features
[`no_optimize`]: #optional-features
[`only_i32`]: #optional-features
[`only_i64`]: #optional-features
[`no_std`]: #optional-features
[`Engine`]: #hello-world
[`Scope`]: #initializing-and-maintaining-state
[`Dynamic`]: #values-and-types
[`OptimizationLevel::Full`]: #optimization-levels

View File

@ -10,7 +10,7 @@ impl TestStruct {
self.x += 1000;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}

View File

@ -10,7 +10,7 @@ impl TestStruct {
self.x += 1000;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}

View File

@ -101,7 +101,7 @@ impl AnyExt for Dynamic {
///
/// # Example
///
/// ```rust
/// ```
/// use rhai::{Dynamic, Any, AnyExt};
///
/// let x: Dynamic = 42_u32.into_dynamic();

View File

@ -23,6 +23,7 @@ use crate::stdlib::{
use crate::stdlib::{fs::File, io::prelude::*, path::PathBuf};
impl<'e> Engine<'e> {
/// Register a custom function.
pub(crate) fn register_fn_raw(
&mut self,
fn_name: &str,
@ -38,13 +39,88 @@ impl<'e> Engine<'e> {
}
/// Register a custom type for use with the `Engine`.
/// The type must be `Clone`.
/// The type must implement `Clone`.
///
/// # Example
///
/// ```
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self { TestStruct { field: 1 } }
/// fn update(&mut self) { self.field += 41; }
/// }
///
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register method on the type.
/// engine.register_fn("update", TestStruct::update);
///
/// assert_eq!(
/// engine.eval::<TestStruct>("let x = new_ts(); x.update(); x")?.field,
/// 42
/// );
/// # Ok(())
/// # }
/// ```
pub fn register_type<T: Any + Clone>(&mut self) {
self.register_type_with_name::<T>(type_name::<T>());
}
/// Register a custom type for use with the `Engine` with a name for the `type_of` function.
/// The type must be `Clone`.
/// Register a custom type for use with the `Engine`, with a pretty-print name
/// for the `type_of` function. The type must implement `Clone`.
///
/// # Example
///
/// ```
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self { TestStruct { field: 1 } }
/// }
///
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// assert_eq!(
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
/// "rust_out::TestStruct"
/// );
///
/// // Register the custom type with a name.
/// engine.register_type_with_name::<TestStruct>("Hello");
///
/// // Register methods on the type.
/// engine.register_fn("new_ts", TestStruct::new);
///
/// assert_eq!(
/// engine.eval::<String>("let x = new_ts(); type_of(x)")?,
/// "Hello"
/// );
/// # Ok(())
/// # }
/// ```
pub fn register_type_with_name<T: Any + Clone>(&mut self, name: &str) {
// Add the pretty-print type name into the map
self.type_names
@ -52,6 +128,7 @@ impl<'e> Engine<'e> {
}
/// Register an iterator adapter for a type with the `Engine`.
/// This is an advanced feature.
pub fn register_iterator<T: Any, F>(&mut self, f: F)
where
F: Fn(&Dynamic) -> Box<dyn Iterator<Item = Dynamic>> + 'static,
@ -60,6 +137,37 @@ impl<'e> Engine<'e> {
}
/// Register a getter function for a member of a registered type with the `Engine`.
///
/// # Example
///
/// ```
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self { TestStruct { field: 1 } }
/// fn get_field(&mut self) -> i64 { self.field }
/// }
///
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a getter on a property (notice it doesn't have to be the same name).
/// engine.register_get("xyz", TestStruct::get_field);
///
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
/// # Ok(())
/// # }
/// ```
pub fn register_get<T: Any + Clone, U: Any + Clone>(
&mut self,
name: &str,
@ -70,6 +178,38 @@ impl<'e> Engine<'e> {
}
/// Register a setter function for a member of a registered type with the `Engine`.
///
/// # Example
///
/// ```
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self { TestStruct { field: 1 } }
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// }
///
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a setter on a property (notice it doesn't have to be the same name)
/// engine.register_set("xyz", TestStruct::set_field);
///
/// // Notice that, with a getter, there is no way to get the property value
/// engine.eval("let a = new_ts(); a.xyz = 42;")?;
/// # Ok(())
/// # }
/// ```
pub fn register_set<T: Any + Clone, U: Any + Clone>(
&mut self,
name: &str,
@ -81,6 +221,39 @@ impl<'e> Engine<'e> {
/// Shorthand for registering both getter and setter functions
/// of a registered type with the `Engine`.
///
/// # Example
///
/// ```
/// #[derive(Clone)]
/// struct TestStruct {
/// field: i64
/// }
///
/// impl TestStruct {
/// fn new() -> Self { TestStruct { field: 1 } }
/// fn get_field(&mut self) -> i64 { self.field }
/// fn set_field(&mut self, new_val: i64) { self.field = new_val; }
/// }
///
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
/// let mut engine = Engine::new();
///
/// // Register the custom type.
/// engine.register_type::<TestStruct>();
///
/// engine.register_fn("new_ts", TestStruct::new);
///
/// // Register a getter and a setter on a property
/// // (notice it doesn't have to be the same name)
/// engine.register_get_set("xyz", TestStruct::get_field, TestStruct::set_field);
///
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz = 42; a.xyz")?, 42);
/// # Ok(())
/// # }
/// ```
pub fn register_get_set<T: Any + Clone, U: Any + Clone>(
&mut self,
name: &str,
@ -91,18 +264,59 @@ impl<'e> Engine<'e> {
self.register_set(name, set_fn);
}
/// Compile a string into an AST.
/// Compile a string into an `AST`, which can be used later for evaluations.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// // Compile a script to an AST and store it for later evaluations
/// let ast = engine.compile("40 + 2")?;
///
/// for _ in 0..42 {
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
/// }
/// # Ok(())
/// # }
/// ```
pub fn compile(&self, input: &str) -> Result<AST, ParseError> {
self.compile_with_scope(&Scope::new(), input)
}
/// Compile a string into an AST using own scope.
/// Compile a string into an `AST` using own scope, which can be used later for evaluations.
/// The scope is useful for passing constants into the script for optimization.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///
/// let mut engine = Engine::new();
///
/// // Create initialized scope
/// let mut scope = Scope::new();
/// scope.push_constant("x", 42_i64); // 'x' is a constant
///
/// // Compile a script to an AST and store it for later evaluations
/// let ast = engine.compile_with_scope(&mut scope,
/// "if x > 40 { x } else { 0 }"
/// )?;
///
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
/// # Ok(())
/// # }
/// ```
pub fn compile_with_scope(&self, scope: &Scope, input: &str) -> Result<AST, ParseError> {
let tokens_stream = lex(input);
parse(&mut tokens_stream.peekable(), self, scope)
}
/// Read the contents of a file into a string.
#[cfg(not(feature = "no_std"))]
fn read_file(path: PathBuf) -> Result<String, EvalAltResult> {
let mut f = File::open(path.clone())
@ -115,14 +329,54 @@ impl<'e> Engine<'e> {
.map(|_| contents)
}
/// Compile a file into an AST.
/// Compile a script file into an `AST`, which can be used later for evaluations.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// // Compile a script file to an AST and store it for later evaluations
/// // Notice that a PathBuf is required which can easily be constructed from a string.
/// let ast = engine.compile_file("script.rhai".into())?;
///
/// for _ in 0..42 {
/// engine.eval_ast::<i64>(&ast)?;
/// }
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
pub fn compile_file(&self, path: PathBuf) -> Result<AST, EvalAltResult> {
self.compile_file_with_scope(&Scope::new(), path)
}
/// Compile a file into an AST using own scope.
/// Compile a script file into an `AST` using own scope, which can be used later for evaluations.
/// The scope is useful for passing constants into the script for optimization.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///
/// let mut engine = Engine::new();
///
/// // Create initialized scope
/// let mut scope = Scope::new();
/// scope.push_constant("x", 42_i64); // 'x' is a constant
///
/// // Compile a script to an AST and store it for later evaluations
/// // Notice that a PathBuf is required which can easily be constructed from a string.
/// let ast = engine.compile_file_with_scope(&mut scope, "script.rhai".into())?;
///
/// let result = engine.eval_ast::<i64>(&ast)?;
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
pub fn compile_file_with_scope(
&self,
@ -135,13 +389,45 @@ impl<'e> Engine<'e> {
})
}
/// Evaluate a file.
/// Evaluate a script file.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// // Notice that a PathBuf is required which can easily be constructed from a string.
/// let result = engine.eval_file::<i64>("script.rhai".into())?;
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
pub fn eval_file<T: Any + Clone>(&mut self, path: PathBuf) -> Result<T, EvalAltResult> {
Self::read_file(path).and_then(|contents| self.eval::<T>(&contents))
}
/// Evaluate a file with own scope.
/// Evaluate a script file with own scope.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///
/// let mut engine = Engine::new();
///
/// // Create initialized scope
/// let mut scope = Scope::new();
/// scope.push("x", 42_i64);
///
/// // Notice that a PathBuf is required which can easily be constructed from a string.
/// let result = engine.eval_file_with_scope::<i64>(&mut scope, "script.rhai".into())?;
/// # Ok(())
/// # }
/// ```
#[cfg(not(feature = "no_std"))]
pub fn eval_file_with_scope<T: Any + Clone>(
&mut self,
@ -152,12 +438,46 @@ impl<'e> Engine<'e> {
}
/// Evaluate a string.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// assert_eq!(engine.eval::<i64>("40 + 2")?, 42);
/// # Ok(())
/// # }
/// ```
pub fn eval<T: Any + Clone>(&mut self, input: &str) -> Result<T, EvalAltResult> {
let mut scope = Scope::new();
self.eval_with_scope(&mut scope, input)
}
/// Evaluate a string with own scope.
///
/// # Example
///
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///
/// let mut engine = Engine::new();
///
/// // Create initialized scope
/// let mut scope = Scope::new();
/// scope.push("x", 40_i64);
///
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 42);
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 44);
///
/// // The variable in the scope is modified
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
/// # Ok(())
/// # }
/// ```
pub fn eval_with_scope<T: Any + Clone>(
&mut self,
scope: &mut Scope,
@ -167,13 +487,55 @@ impl<'e> Engine<'e> {
self.eval_ast_with_scope(scope, &ast)
}
/// Evaluate an AST.
/// Evaluate an `AST`.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
/// let mut engine = Engine::new();
///
/// // Compile a script to an AST and store it for later evaluations
/// let ast = engine.compile("40 + 2")?;
///
/// // Evaluate it
/// assert_eq!(engine.eval_ast::<i64>(&ast)?, 42);
/// # Ok(())
/// # }
/// ```
pub fn eval_ast<T: Any + Clone>(&mut self, ast: &AST) -> Result<T, EvalAltResult> {
let mut scope = Scope::new();
self.eval_ast_with_scope(&mut scope, ast)
}
/// Evaluate an AST with own scope.
/// Evaluate an `AST` with own scope.
///
/// # Example
///
/// ```no_run
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///
/// let mut engine = Engine::new();
///
/// // Compile a script to an AST and store it for later evaluations
/// let ast = engine.compile("x + 2")?;
///
/// // Create initialized scope
/// let mut scope = Scope::new();
/// scope.push("x", 40_i64);
///
/// // Evaluate it
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 42);
/// assert_eq!(engine.eval_with_scope::<i64>(&mut scope, "x = x + 2; x")?, 44);
///
/// // The variable in the scope is modified
/// assert_eq!(scope.get_value::<i64>("x").expect("variable x should exist"), 44);
/// # Ok(())
/// # }
/// ```
pub fn eval_ast_with_scope<T: Any + Clone>(
&mut self,
scope: &mut Scope,
@ -221,8 +583,7 @@ impl<'e> Engine<'e> {
/// Evaluate a file, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_ and not cleared from run to run.
#[cfg(not(feature = "no_std"))]
pub fn consume_file(
&mut self,
@ -235,8 +596,7 @@ impl<'e> Engine<'e> {
/// Evaluate a file with own scope, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_ and not cleared from run to run.
#[cfg(not(feature = "no_std"))]
pub fn consume_file_with_scope(
&mut self,
@ -251,8 +611,7 @@ impl<'e> Engine<'e> {
/// Evaluate a string, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_and not cleared from run to run.
pub fn consume(&mut self, retain_functions: bool, input: &str) -> Result<(), EvalAltResult> {
self.consume_with_scope(&mut Scope::new(), retain_functions, input)
}
@ -260,8 +619,7 @@ impl<'e> Engine<'e> {
/// Evaluate a string with own scope, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_and not cleared from run to run.
pub fn consume_with_scope(
&mut self,
scope: &mut Scope,
@ -279,17 +637,15 @@ impl<'e> Engine<'e> {
/// Evaluate an AST, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_and not cleared from run to run.
pub fn consume_ast(&mut self, retain_functions: bool, ast: &AST) -> Result<(), EvalAltResult> {
self.consume_ast_with_scope(&mut Scope::new(), retain_functions, ast)
}
/// Evaluate an AST with own scope, but throw away the result and only return error (if any).
/// Evaluate an `AST` with own scope, but throw away the result and only return error (if any).
/// Useful for when you don't need the result, but still need to keep track of possible errors.
///
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_
/// and not cleared from run to run.
/// Note - if `retain_functions` is set to `true`, functions defined by previous scripts are _retained_and not cleared from run to run.
pub fn consume_ast_with_scope(
&mut self,
scope: &mut Scope,
@ -341,7 +697,7 @@ impl<'e> Engine<'e> {
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// # #[cfg(not(feature = "no_stdlib"))]
/// # #[cfg(not(feature = "no_function"))]
@ -350,8 +706,10 @@ impl<'e> Engine<'e> {
///
/// let mut engine = Engine::new();
///
/// // Set 'retain_functions' in 'consume' to keep the function definitions
/// engine.consume(true, "fn add(x, y) { x.len() + y }")?;
///
/// // Call the script-defined function
/// let result: i64 = engine.call_fn("add", (String::from("abc"), 123_i64))?;
///
/// assert_eq!(result, 126);
@ -388,17 +746,17 @@ impl<'e> Engine<'e> {
})
}
/// Optimize the AST with constants defined in an external Scope.
/// An optimized copy of the AST is returned while the original AST is untouched.
/// Optimize the `AST` with constants defined in an external Scope.
/// An optimized copy of the `AST` is returned while the original `AST` is untouched.
///
/// Although optimization is performed by default during compilation, sometimes it is necessary to
/// _re_-optimize an AST. For example, when working with constants that are passed in via an
/// external scope, it will be more efficient to optimize the AST once again to take advantage
/// external scope, it will be more efficient to optimize the `AST` once again to take advantage
/// of the new constants.
///
/// With this method, it is no longer necessary to recompile a large script. The script AST can be
/// With this method, it is no longer necessary to recompile a large script. The script `AST` can be
/// compiled just once. Before evaluation, constants are passed into the `Engine` via an external scope
/// (i.e. with `scope.push_constant(...)`). Then, the AST is cloned and the copy re-optimized before running.
/// (i.e. with `scope.push_constant(...)`). Then, the `AST is cloned and the copy re-optimized before running.
#[cfg(not(feature = "no_optimize"))]
pub fn optimize_ast(&self, scope: &Scope, ast: &AST) -> AST {
let statements = ast.0.clone();
@ -411,7 +769,7 @@ impl<'e> Engine<'e> {
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///
@ -435,7 +793,7 @@ impl<'e> Engine<'e> {
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///

View File

@ -57,7 +57,7 @@ pub struct FnSpec<'a> {
/// Rhai main scripting engine.
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::Engine;
///

View File

@ -10,10 +10,12 @@ use crate::result::EvalAltResult;
use crate::stdlib::{any::TypeId, boxed::Box, string::ToString, vec};
/// A trait to register custom functions with the `Engine`.
pub trait RegisterFn<FN, ARGS, RET> {
/// Register a custom function with the `Engine`.
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
///
@ -27,72 +29,71 @@ use crate::stdlib::{any::TypeId, boxed::Box, string::ToString, vec};
/// // You must use the trait rhai::RegisterFn to get this method.
/// engine.register_fn("add", add);
///
/// let result = engine.eval::<i64>("add(40, 2)")?;
/// assert_eq!(engine.eval::<i64>("add(40, 2)")?, 42);
///
/// println!("Answer: {}", result); // prints 42
/// // You can also register a closure.
/// engine.register_fn("sub", |x: i64, y: i64| x - y );
///
/// assert_eq!(engine.eval::<i64>("sub(44, 2)")?, 42);
/// # Ok(())
/// # }
/// ```
pub trait RegisterFn<FN, ARGS, RET> {
/// Register a custom function with the `Engine`.
fn register_fn(&mut self, name: &str, f: FN);
}
/// A trait to register custom functions that return `Dynamic` values with the `Engine`.
pub trait RegisterDynamicFn<FN, ARGS> {
/// Register a custom function returning `Dynamic` values with the `Engine`.
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Dynamic, RegisterDynamicFn};
///
/// // Function that returns a Dynamic value
/// fn get_an_any(x: i64) -> Dynamic {
/// fn return_the_same_as_dynamic(x: i64) -> Dynamic {
/// Box::new(x)
/// }
///
/// let mut engine = Engine::new();
///
/// // You must use the trait rhai::RegisterDynamicFn to get this method.
/// engine.register_dynamic_fn("get_an_any", get_an_any);
/// engine.register_dynamic_fn("get_any_number", return_the_same_as_dynamic);
///
/// let result = engine.eval::<i64>("get_an_any(42)")?;
///
/// println!("Answer: {}", result); // prints 42
/// assert_eq!(engine.eval::<i64>("get_any_number(42)")?, 42);
/// # Ok(())
/// # }
/// ```
pub trait RegisterDynamicFn<FN, ARGS> {
/// Register a custom function returning `Dynamic` values with the `Engine`.
fn register_dynamic_fn(&mut self, name: &str, f: FN);
}
/// A trait to register fallible custom functions returning Result<_, EvalAltResult> with the `Engine`.
pub trait RegisterResultFn<FN, ARGS, RET> {
/// Register a custom fallible function with the `Engine`.
///
/// # Example
///
/// ```rust
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, RegisterFn};
/// ```
/// use rhai::{Engine, RegisterResultFn, EvalAltResult};
///
/// // Normal function
/// fn add(x: i64, y: i64) -> i64 {
/// x + y
/// fn div(x: i64, y: i64) -> Result<i64, EvalAltResult> {
/// if y == 0 {
/// Err("division by zero!".into()) // '.into()' automatically converts to 'EvalAltResult::ErrorRuntime'
/// } else {
/// Ok(x / y)
/// }
/// }
///
/// let mut engine = Engine::new();
///
/// // You must use the trait rhai::RegisterFn to get this method.
/// engine.register_fn("add", add);
/// // You must use the trait rhai::RegisterResultFn to get this method.
/// engine.register_result_fn("div", div);
///
/// let result = engine.eval::<i64>("add(40, 2)")?;
///
/// println!("Answer: {}", result); // prints 42
/// # Ok(())
/// # }
/// engine.eval::<i64>("div(42, 0)")
/// .expect_err("expecting division by zero error!");
/// ```
pub trait RegisterResultFn<FN, ARGS, RET> {
/// Register a custom function with the `Engine`.
fn register_result_fn(&mut self, name: &str, f: FN);
}

View File

@ -5,7 +5,7 @@
//! It provides a familiar syntax based on JS and Rust and a simple Rust interface.
//! Here is a quick example. First, the contents of `my_script.rhai`:
//!
//! ```rust,ignore
//! ```,ignore
//! fn factorial(x) {
//! if x == 1 { return 1; }
//! x * factorial(x - 1)
@ -16,7 +16,7 @@
//!
//! And the Rust part:
//!
//! ```rust,no_run
//! ```,no_run
//! use rhai::{Engine, EvalAltResult, RegisterFn};
//!
//! fn main() -> Result<(), EvalAltResult>

View File

@ -36,7 +36,7 @@ pub struct ScopeEntry<'a> {
///
/// # Example
///
/// ```rust
/// ```
/// # fn main() -> Result<(), rhai::EvalAltResult> {
/// use rhai::{Engine, Scope};
///

View File

@ -35,7 +35,7 @@ fn test_array_with_structs() -> Result<(), EvalAltResult> {
self.x = new_x;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}

View File

@ -38,7 +38,7 @@ fn struct_with_float() -> Result<(), EvalAltResult> {
self.x = new_x;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1.0 }
}
}

View File

@ -16,7 +16,7 @@ fn test_get_set() -> Result<(), EvalAltResult> {
self.x = new_x;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}

View File

@ -12,7 +12,7 @@ fn test_method_call() -> Result<(), EvalAltResult> {
self.x += 1000;
}
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}

View File

@ -19,7 +19,7 @@ fn test_mismatched_op_custom_type() {
}
impl TestStruct {
fn new() -> TestStruct {
fn new() -> Self {
TestStruct { x: 1 }
}
}