reorganize module
This commit is contained in:
		
							
								
								
									
										146
									
								
								_archive/rhai_engine/rhaibook/rust/build-type.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								_archive/rhai_engine/rhaibook/rust/build-type.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,146 @@
 | 
			
		||||
Register a Custom Type via the Type Builder
 | 
			
		||||
===========================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Warning"
 | 
			
		||||
 | 
			
		||||
This assumes that the type is defined within the current crate and you can implement traits for it.
 | 
			
		||||
 | 
			
		||||
However, you may not _control_ the type (it may be auto-generated or maintained by another user),
 | 
			
		||||
so you cannot put attributes on it.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It is usually convenient to package a [custom type]'s API (i.e. [methods],
 | 
			
		||||
[properties][getters/setters], [indexers] and [type iterators]) together such that they can be more
 | 
			
		||||
easily managed.
 | 
			
		||||
 | 
			
		||||
This can be achieved by manually implementing the `CustomType` trait, which contains only a single method:
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> fn build(builder: TypeBuilder<T>)
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
The `TypeBuilder` parameter provides a range of convenient methods to register [methods], property
 | 
			
		||||
[getters/setters], [indexers] and [type iterators] of a [custom type]:
 | 
			
		||||
 | 
			
		||||
| Method                 | Description                                                               |
 | 
			
		||||
| ---------------------- | ------------------------------------------------------------------------- |
 | 
			
		||||
| `with_name`            | set a friendly name                                                       |
 | 
			
		||||
| `on_print`             | register the [`to_string`] function that pretty-prints the [custom type]  |
 | 
			
		||||
| `on_debug`             | register the [`to_debug`] function that debug-prints the [custom type]    |
 | 
			
		||||
| `with_fn`              | register a [method] (or any function really)                              |
 | 
			
		||||
| `with_get`             | register a property [getter][getters/setters]                             |
 | 
			
		||||
| `with_set`             | register a property [getter][getters/setters]                             |
 | 
			
		||||
| `with_get_set`         | register property [getters/setters]                                       |
 | 
			
		||||
| `with_indexer_get`     | register an [indexer] get function                                        |
 | 
			
		||||
| `with_indexer_set`     | register an [indexer] set function                                        |
 | 
			
		||||
| `with_indexer_get_set` | register [indexer] get/set functions                                      |
 | 
			
		||||
| `is_iterable`          | automatically register a [type iterator] if the [custom type] is iterable |
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Use plugin module if starting from scratch"
 | 
			
		||||
 | 
			
		||||
The `CustomType` trait is typically used on external types that are already defined.
 | 
			
		||||
 | 
			
		||||
To define a [custom type] and implement its API from scratch, it is more convenient to use a [plugin module].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Custom type
 | 
			
		||||
#[derive(Debug, Clone, Eq, PartialEq)]
 | 
			
		||||
struct Vec3 {
 | 
			
		||||
    x: i64,
 | 
			
		||||
    y: i64,
 | 
			
		||||
    z: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Custom type API
 | 
			
		||||
impl Vec3 {
 | 
			
		||||
    fn new(x: i64, y: i64, z: i64) -> Self {
 | 
			
		||||
        Self { x, y, z }
 | 
			
		||||
    }
 | 
			
		||||
    fn get_x(&mut self) -> i64 {
 | 
			
		||||
        self.x
 | 
			
		||||
    }
 | 
			
		||||
    fn set_x(&mut self, x: i64) {
 | 
			
		||||
        self.x = x
 | 
			
		||||
    }
 | 
			
		||||
    fn get_y(&mut self) -> i64 {
 | 
			
		||||
        self.y
 | 
			
		||||
    }
 | 
			
		||||
    fn set_y(&mut self, y: i64) {
 | 
			
		||||
        self.y = y
 | 
			
		||||
    }
 | 
			
		||||
    fn get_z(&mut self) -> i64 {
 | 
			
		||||
        self.z
 | 
			
		||||
    }
 | 
			
		||||
    fn set_z(&mut self, z: i64) {
 | 
			
		||||
        self.z = z
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The custom type can even be iterated!
 | 
			
		||||
impl IntoIterator for Vec3 {
 | 
			
		||||
    type Item = i64;
 | 
			
		||||
    type IntoIter = std::vec::IntoIter<Self::Item>;
 | 
			
		||||
 | 
			
		||||
    fn into_iter(self) -> Self::IntoIter {
 | 
			
		||||
        vec![self.x, self.y, self.z].into_iter()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Use 'CustomType' to register the entire API
 | 
			
		||||
impl CustomType for Vec3 {
 | 
			
		||||
    fn build(mut builder: TypeBuilder<Self>) {
 | 
			
		||||
        builder
 | 
			
		||||
            .with_name("Vec3")
 | 
			
		||||
            .with_fn("vec3", Self::new)
 | 
			
		||||
            .is_iterable()
 | 
			
		||||
            .with_get_set("x", Self::get_x, Self::set_x)
 | 
			
		||||
            .with_get_set("y", Self::get_y, Self::set_y)
 | 
			
		||||
            .with_get_set("z", Self::get_z, Self::set_z)
 | 
			
		||||
            // Indexer get/set functions that do not panic on invalid indices
 | 
			
		||||
            .with_indexer_get_set(
 | 
			
		||||
                |vec: &mut Self, idx: i64) -> Result<i64, Box<EvalAltResult>> {
 | 
			
		||||
                    match idx {
 | 
			
		||||
                        0 => Ok(vec.x),
 | 
			
		||||
                        1 => Ok(vec.y),
 | 
			
		||||
                        2 => Ok(vec.z),
 | 
			
		||||
                        _ => Err(EvalAltResult::ErrorIndexNotFound(idx.Into(), Position::NONE).into()),
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
                |vec: &mut Self, idx: i64, value: i64) -> Result<(), Box<EvalAltResult>> {
 | 
			
		||||
                    match idx {
 | 
			
		||||
                        0 => vec.x = value,
 | 
			
		||||
                        1 => vec.y = value,
 | 
			
		||||
                        2 => vec.z = value,
 | 
			
		||||
                        _ => Err(EvalAltResult::ErrorIndexNotFound(idx.Into(), Position::NONE).into()),
 | 
			
		||||
                    }
 | 
			
		||||
                    Ok(())
 | 
			
		||||
                }
 | 
			
		||||
            );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Register the custom type in one go!
 | 
			
		||||
engine.build_type::<Vec3>();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish question "TL;DR – Why isn't there `is_indexable`?"
 | 
			
		||||
 | 
			
		||||
Technically speaking, `TypeBuilder` can automatically register an [indexer] get function if the [custom type] implements `Index`.
 | 
			
		||||
Similarly, it can automatically register an [indexer] set function for `IndexMut`.
 | 
			
		||||
 | 
			
		||||
In practice, however, this is usually not desirable because most `Index`/`IndexMut` implementations panic on invalid indices.
 | 
			
		||||
 | 
			
		||||
For Rhai, it is necessary to handle invalid indices properly by returning an error.
 | 
			
		||||
 | 
			
		||||
Therefore, in the example above, the `with_indexer_get_set` method properly handles invalid indices by returning errors.
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										139
									
								
								_archive/rhai_engine/rhaibook/rust/collections.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								_archive/rhai_engine/rhaibook/rust/collections.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,139 @@
 | 
			
		||||
Custom Collection Types
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.side "Tip"
 | 
			
		||||
 | 
			
		||||
Collections can also hold [`Dynamic`] values (e.g. like an [array]).
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
A _collection_ type holds a... well... _collection_ of items.  It can be homogeneous (all items are
 | 
			
		||||
the same type) or heterogeneous (items are of different types, use [`Dynamic`] to hold).
 | 
			
		||||
 | 
			
		||||
Because their only purpose for existence is to hold a number of items, collection types commonly
 | 
			
		||||
register the following methods.
 | 
			
		||||
 | 
			
		||||
<section></section>
 | 
			
		||||
 | 
			
		||||
| Method                    | Description                                                      |
 | 
			
		||||
| ------------------------- | ---------------------------------------------------------------- |
 | 
			
		||||
| `len` method and property | gets the total number of items in the collection                 |
 | 
			
		||||
| `clear`                   | clears the collection                                            |
 | 
			
		||||
| `contains`                | checks if a particular item exists in the collection             |
 | 
			
		||||
| `add`, `+=` operator      | adds a particular item to the collection                         |
 | 
			
		||||
| `remove`, `-=` operator   | removes a particular item from the collection                    |
 | 
			
		||||
| `merge` or `+` operator   | merges two collections, yielding a new collection with all items |
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Define type iterator"
 | 
			
		||||
 | 
			
		||||
Collections are typically iterable.
 | 
			
		||||
 | 
			
		||||
It is customary to use `Engine::register_iterator` to allow iterating the collection if
 | 
			
		||||
it implements `IntoIterator`.
 | 
			
		||||
 | 
			
		||||
Alternative, register a specific [type iterator] for the [custom type].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Use a plugin module"
 | 
			
		||||
 | 
			
		||||
A [plugin module] makes defining an entire API for a [custom type] a snap.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
type MyBag = HashSet<MyItem>;
 | 
			
		||||
 | 
			
		||||
engine
 | 
			
		||||
    .register_type_with_name::<MyBag>("MyBag")
 | 
			
		||||
    .register_iterator::<MyBag>()
 | 
			
		||||
    .register_fn("new_bag", || MyBag::new())
 | 
			
		||||
    .register_fn("len", |col: &mut MyBag| col.len() as i64)
 | 
			
		||||
    .register_get("len", |col: &mut MyBag| col.len() as i64)
 | 
			
		||||
    .register_fn("clear", |col: &mut MyBag| col.clear())
 | 
			
		||||
    .register_fn("contains", |col: &mut MyBag, item: i64| col.contains(&item))
 | 
			
		||||
    .register_fn("add", |col: &mut MyBag, item: MyItem| col.insert(item))
 | 
			
		||||
    .register_fn("+=", |col: &mut MyBag, item: MyItem| col.insert(item))
 | 
			
		||||
    .register_fn("remove", |col: &mut MyBag, item: MyItem| col.remove(&item))
 | 
			
		||||
    .register_fn("-=", |col: &mut MyBag, item: MyItem| col.remove(&item))
 | 
			
		||||
    .register_fn("+", |mut col1: MyBag, col2: MyBag| {
 | 
			
		||||
        col1.extend(col2.into_iter());
 | 
			
		||||
        col1
 | 
			
		||||
    });
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
What About Indexers?
 | 
			
		||||
--------------------
 | 
			
		||||
 | 
			
		||||
Many users are tempted to register [indexers] for custom collections.  This essentially makes the
 | 
			
		||||
original Rust type something similar to `Vec<MyType>`.
 | 
			
		||||
 | 
			
		||||
Rhai's standard [`Array`] type is `Vec<Dynamic>` which already holds an ordered, iterable and
 | 
			
		||||
indexable collection of dynamic items.  Since Rhai has built-in support, manipulating [arrays] is fast.
 | 
			
		||||
 | 
			
		||||
In _most_ circumstances, it is better to use [`Array`] instead of a [custom type].
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Convert to `Array` using `.into()`"
 | 
			
		||||
 | 
			
		||||
[`Dynamic`] implements `FromIterator` for all iterable types and an [`Array`] is created in the process.
 | 
			
		||||
 | 
			
		||||
So, converting a typed array (i.e. `Vec<MyType>`) into an [array] in Rhai is as simple as calling `.into()`.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Say you have a custom typed array...
 | 
			
		||||
let my_custom_array: Vec<MyType> = do_lots_of_calc(42);
 | 
			
		||||
 | 
			
		||||
// Convert it into a 'Dynamic' that holds an array
 | 
			
		||||
let value: Dynamic = my_custom_array.into();
 | 
			
		||||
 | 
			
		||||
// Use is anywhere in Rhai...
 | 
			
		||||
scope.push("my_custom_array", value);
 | 
			
		||||
 | 
			
		||||
engine
 | 
			
		||||
    // Raw function that returns a custom type
 | 
			
		||||
    .register_fn("do_lots_of_calc_raw", do_lots_of_calc)
 | 
			
		||||
    // Wrap function that return a custom typed array
 | 
			
		||||
    .register_fn("do_lots_of_calc", |seed: i64| -> Dynamic {
 | 
			
		||||
        let result = do_lots_of_calc(seed);     // Vec<MyType>
 | 
			
		||||
        result.into()                           // Array in Dynamic
 | 
			
		||||
    });
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TL;DR
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
~~~admonish question "Why shouldn't we register `Vec<MyType>`?"
 | 
			
		||||
 | 
			
		||||
### Reason #1: Performance
 | 
			
		||||
 | 
			
		||||
A main reason why anybody would want to do this is to avoid the overhead of storing [`Dynamic`] items.
 | 
			
		||||
 | 
			
		||||
This is why [BLOB's] is a built-in data type in Rhai, even though it is actually defined as `Vec<u8>`.
 | 
			
		||||
The overhead of using [`Dynamic`] (16 bytes) versus `u8` (1 byte) is worth the trouble, although the
 | 
			
		||||
performance gains may not be as pronounced as expected: benchmarks show a 15% speed improvement inside
 | 
			
		||||
a tight loop compared with using an [array].
 | 
			
		||||
 | 
			
		||||
`Vec<MyType>`, however, will be treated as an opaque [custom type] in Rhai, so performance is not optimized.
 | 
			
		||||
What you gain from avoiding [`Dynamic`], you pay back in terms of slower access to the `Vec` as well as `MyType`
 | 
			
		||||
(which is treated as yet another opaque [custom type]).
 | 
			
		||||
 | 
			
		||||
### Reason #2: API
 | 
			
		||||
 | 
			
		||||
Another reason why it shouldn't be done is due to the large number of functions and methods that must be registered
 | 
			
		||||
for each type of this sort.  One only has to look at the vast API surface of [arrays]({{rootUrl}}/language/arrays.md#built-in-functions)
 | 
			
		||||
to see the common methods that a user would expect to be available.
 | 
			
		||||
 | 
			
		||||
Since `Vec<Type>` looks, feels and quacks just like a normal [array], and the usage syntax is almost equivalent (except
 | 
			
		||||
for the fact that the data type is restricted), users would be frustrated if they find that certain functions available for
 | 
			
		||||
[arrays] are not provided.
 | 
			
		||||
 | 
			
		||||
This is similar to JavaScript's [_Typed Arrays_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays).
 | 
			
		||||
They are quite awkward to work with, and basically each has a full API definition that must be pre-registered.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								_archive/rhai_engine/rhaibook/rust/context-restore.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								_archive/rhai_engine/rhaibook/rust/context-restore.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
			
		||||
Advanced Usage – Restore `NativeCallContext`
 | 
			
		||||
==================================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The [`NativeCallContext`] type encapsulates the entire _context_ of a script up to the
 | 
			
		||||
particular point of the native Rust function call.
 | 
			
		||||
 | 
			
		||||
The data inside a [`NativeCallContext`] can be stored (as a type `NativeCallContextStore`) for later
 | 
			
		||||
use, when a new [`NativeCallContext`] can be constructed based on these stored data.
 | 
			
		||||
 | 
			
		||||
A reconstructed [`NativeCallContext`] acts almost the same as the original instance, so it is possible
 | 
			
		||||
to suspend the evaluation of a script, and to continue at a later time with a new
 | 
			
		||||
[`NativeCallContext`].
 | 
			
		||||
 | 
			
		||||
Doing so requires the [`internals`] feature to access internal APIs.
 | 
			
		||||
 | 
			
		||||
### Step 1: Store `NativeCallContext` data
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Store context for later use
 | 
			
		||||
let context_data = context.store_data();
 | 
			
		||||
 | 
			
		||||
// ... store 'context_data' somewhere ...
 | 
			
		||||
secret_database.push(context_data);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Step 2: Restore `NativeCallContext`
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// ... do something else ...
 | 
			
		||||
 | 
			
		||||
// Restore the context
 | 
			
		||||
let context_data = secret_database.get();
 | 
			
		||||
 | 
			
		||||
let new_context = context_data.create_context(&engine);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										110
									
								
								_archive/rhai_engine/rhaibook/rust/context.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								_archive/rhai_engine/rhaibook/rust/context.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
`NativeCallContext`
 | 
			
		||||
===================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
If the _first_ parameter of a function is of type `rhai::NativeCallContext`, then it is treated
 | 
			
		||||
specially by the [`Engine`].
 | 
			
		||||
 | 
			
		||||
`NativeCallContext` is a type that encapsulates the current _call context_ of a Rust function call
 | 
			
		||||
and exposes the following.
 | 
			
		||||
 | 
			
		||||
| Method                    |                      Return type                       | Description                                                                                                                                                                                                                                |
 | 
			
		||||
| ------------------------- | :----------------------------------------------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
 | 
			
		||||
| `engine()`                |                 [`&Engine`][`Engine`]                  | the current [`Engine`], with all configurations and settings.<br/>This is sometimes useful for calling a script-defined function within the same evaluation context using [`Engine::call_fn`][`call_fn`], or calling a [function pointer]. |
 | 
			
		||||
| `fn_name()`               |                         `&str`                         | name of the function called (useful when the same Rust function is mapped to multiple Rhai-callable function names)                                                                                                                        |
 | 
			
		||||
| `source()`                |                     `Option<&str>`                     | reference to the current source, if any                                                                                                                                                                                                    |
 | 
			
		||||
| `position()`              |                       `Position`                       | position of the function call                                                                                                                                                                                                              |
 | 
			
		||||
| `call_level()`            |                        `usize`                         | the current nesting level of function calls                                                                                                                                                                                                |
 | 
			
		||||
| `tag()`                   |                [`&Dynamic`][`Dynamic`]                 | reference to the _custom state_ that is persistent during the current run                                                                                                                                                                  |
 | 
			
		||||
| `iter_imports()`          | `impl Iterator<Item = (&str,`[`&Module`][`Module`]`)>` | iterator of the current stack of [modules] imported via `import` statements, in reverse order (i.e. later [modules] come first)                                                                                                            |
 | 
			
		||||
| `global_runtime_state()`  |     [`&GlobalRuntimeState`][`GlobalRuntimeState`]      | reference to the current [global runtime state][`GlobalRuntimeState`] (including the stack of [modules] imported via `import` statements); requires the [`internals`] feature                                                              |
 | 
			
		||||
| `iter_namespaces()`       |     `impl Iterator<Item =`[`&Module`][`Module`]`>`     | iterator of the [namespaces][function namespaces] (as [modules]) containing all script-defined [functions], in reverse order (i.e. later [modules] come first)                                                                             |
 | 
			
		||||
| `namespaces()`            |                [`&[&Module]`][`Module`]                | reference to the [namespaces][function namespaces] (as [modules]) containing all script-defined [functions]; requires the [`internals`] feature                                                                                            |
 | 
			
		||||
| `call_fn(...)`            |            `Result<T, Box<EvalAltResult>>`             | call a function with the supplied arguments, casting the result into the required type                                                                                                                                                     |
 | 
			
		||||
| `call_native_fn(...)`     |            `Result<T, Box<EvalAltResult>>`             | call a registered native Rust function with the supplied arguments, casting the result into the required type                                                                                                                              |
 | 
			
		||||
| `call_fn_raw(...)`        |      `Result<`[`Dynamic`]`, Box<EvalAltResult>>`       | call a function with the supplied arguments; this is an advanced method                                                                                                                                                                    |
 | 
			
		||||
| `call_native_fn_raw(...)` |      `Result<`[`Dynamic`]`, Box<EvalAltResult>>`       | call a registered native Rust function with the supplied arguments; this is an advanced method                                                                                                                                             |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example Implementations
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
~~~admonish example "Example – Implement Safety Checks"
 | 
			
		||||
 | 
			
		||||
The native call context is useful for protecting a function from malicious scripts.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Array, NativeCallContext, EvalAltResult, Position};
 | 
			
		||||
 | 
			
		||||
// This function builds an array of arbitrary size, but is protected against attacks
 | 
			
		||||
// by first checking with the allowed limit set into the 'Engine'.
 | 
			
		||||
pub fn new_array(context: NativeCallContext, size: i64) -> Result<Array, Box<EvalAltResult>>
 | 
			
		||||
{
 | 
			
		||||
    let array = Array::new();
 | 
			
		||||
 | 
			
		||||
    if size <= 0 {
 | 
			
		||||
        return array;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let size = size as usize;
 | 
			
		||||
    let max_size = context.engine().max_array_size();
 | 
			
		||||
 | 
			
		||||
    // Make sure the function does not generate a data structure larger than
 | 
			
		||||
    // the allowed limit for the Engine!
 | 
			
		||||
    if max_size > 0 && size > max_size {
 | 
			
		||||
        return Err(EvalAltResult::ErrorDataTooLarge(
 | 
			
		||||
            "Size to grow".to_string(),
 | 
			
		||||
            max_size, size,
 | 
			
		||||
            context.position(),
 | 
			
		||||
        ).into());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    for x in 0..size {
 | 
			
		||||
        array.push(x.into());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    OK(array)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
~~~admonish example "Example – Call a Function Within a Function"
 | 
			
		||||
 | 
			
		||||
The _native call context_ can be used to call a [function] within the current evaluation
 | 
			
		||||
via `call_fn` (or more commonly `call_native_fn`).
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, NativeCallContext};
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// A function expecting a callback in form of a function pointer.
 | 
			
		||||
engine.register_fn("super_call", |context: NativeCallContext, value: i64| {
 | 
			
		||||
    // Call a function within the current evaluation!
 | 
			
		||||
    // 'call_native_fn' ensures that only registered native Rust functions
 | 
			
		||||
    // are called, so a scripted function named 'double' cannot hijack
 | 
			
		||||
    // the process.
 | 
			
		||||
    // To also include scripted functions, use 'call_fn' instead.
 | 
			
		||||
    context.call_native_fn::<i64>("double", (value,))
 | 
			
		||||
    //                                      ^^^^^^^^ arguments passed in tuple
 | 
			
		||||
});
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
~~~admonish example "Example – Implement a Callback"
 | 
			
		||||
 | 
			
		||||
The _native call context_ can be used to call a [function pointer] or [closure] that has been passed
 | 
			
		||||
as a parameter to the function (via `FnPtr::call_within_context`), thereby implementing a _callback_.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Dynamic, FnPtr, NativeCallContext, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
pub fn greet(context: NativeCallContext, callback: FnPtr) -> Result<String, Box<EvalAltResult>>
 | 
			
		||||
{
 | 
			
		||||
    // Call the callback closure with the current evaluation context!
 | 
			
		||||
    let name = callback.call_within_context(&context, ())?;
 | 
			
		||||
    Ok(format!("hello, {}!", name))
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										97
									
								
								_archive/rhai_engine/rhaibook/rust/custom-types.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								_archive/rhai_engine/rhaibook/rust/custom-types.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,97 @@
 | 
			
		||||
Working with Any Rust Type
 | 
			
		||||
===========================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish tip.side "Tip: Shared types"
 | 
			
		||||
 | 
			
		||||
The only requirement of a type to work with Rhai is `Clone`.
 | 
			
		||||
 | 
			
		||||
Therefore, it is extremely easy to use Rhai with data types such as
 | 
			
		||||
`Rc<...>`, `Arc<...>`, `Rc<RefCell<...>>`, `Arc<Mutex<...>>` etc.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish note.side "Under `sync`"
 | 
			
		||||
 | 
			
		||||
If the [`sync`] feature is used, a custom type must also be `Send + Sync`.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
Rhai works seamlessly with any Rust type, as long as it implements `Clone` as this allows the
 | 
			
		||||
[`Engine`] to pass by value.
 | 
			
		||||
 | 
			
		||||
A type that is not one of the [standard types] is termed a "custom type".
 | 
			
		||||
 | 
			
		||||
Custom types can have the following:
 | 
			
		||||
 | 
			
		||||
* a custom (friendly) display name
 | 
			
		||||
 | 
			
		||||
* [methods]
 | 
			
		||||
 | 
			
		||||
* [property getters and setters](getters/setters)
 | 
			
		||||
 | 
			
		||||
* [indexers]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Free Typing
 | 
			
		||||
-----------
 | 
			
		||||
 | 
			
		||||
```admonish question.side "Why \\"Custom\\"?"
 | 
			
		||||
 | 
			
		||||
Rhai internally supports a number of standard data types (see [this list][standard types]).
 | 
			
		||||
 | 
			
		||||
Any type outside of the list is considered _custom_.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.side "Custom types are slower"
 | 
			
		||||
 | 
			
		||||
Custom types run _slower_ than [built-in types][standard types] due to an additional
 | 
			
		||||
level of indirection, but for all other purposes there is no difference.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Rhai works seamlessly with _any_ Rust type.
 | 
			
		||||
 | 
			
		||||
A custom type is stored in Rhai as a Rust _trait object_ (specifically, a `dyn rhai::Variant`),
 | 
			
		||||
with no restrictions other than being `Clone` (plus `Send + Sync` under the [`sync`] feature).
 | 
			
		||||
 | 
			
		||||
The type literally does not have any prerequisite other than being `Clone`.
 | 
			
		||||
 | 
			
		||||
It does not need to implement any other trait or use any custom `#[derive]`.
 | 
			
		||||
 | 
			
		||||
This allows Rhai to be integrated into an existing Rust code base with as little plumbing as
 | 
			
		||||
possible, usually silently and seamlessly.
 | 
			
		||||
 | 
			
		||||
External types that are not defined within the same crate (and thus cannot implement special Rhai
 | 
			
		||||
traits or use special `#[derive]`) can also be used easily with Rhai.
 | 
			
		||||
 | 
			
		||||
Support for custom types can be turned off via the [`no_object`] feature.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Register API
 | 
			
		||||
------------
 | 
			
		||||
 | 
			
		||||
For Rhai scripts to interact with the custom type, and API must be registered for it with the [`Engine`].
 | 
			
		||||
 | 
			
		||||
The API can consist of functions, [methods], property [getters/setters], [indexers],
 | 
			
		||||
[iterators][type iterators] etc.
 | 
			
		||||
 | 
			
		||||
There are three ways to register an API for a custom type.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### 1. Auto-Generate API
 | 
			
		||||
 | 
			
		||||
If you have complete control of the type, then this is the easiest way.
 | 
			
		||||
 | 
			
		||||
The [`#[derive(CustomType)]`](derive-custom-type.md) macro can be used to automatically generate an
 | 
			
		||||
API for a custom type via the [`CustomType`] trait.
 | 
			
		||||
 | 
			
		||||
### 2. Custom Type Builder
 | 
			
		||||
 | 
			
		||||
For types in the same crate that you do not control, each function, [method], property [getter/setter][getters/setters],
 | 
			
		||||
[indexer] and [iterator][type iterator] can be registered manually, as a single package, via the [`CustomType`] trait
 | 
			
		||||
using the _Custom Type Builder_.
 | 
			
		||||
 | 
			
		||||
### 3. Manual Registration
 | 
			
		||||
 | 
			
		||||
For external types that cannot implement the [`CustomType`] trait due to Rust's [_orphan rule_](https://doc.rust-lang.org/book/ch10-02-traits.html),
 | 
			
		||||
each function, [method], property [getter/setter][getters/setters], [indexer] and [iterator][type iterator]
 | 
			
		||||
must be registered manually with the [`Engine`].
 | 
			
		||||
							
								
								
									
										227
									
								
								_archive/rhai_engine/rhaibook/rust/derive-custom-type.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										227
									
								
								_archive/rhai_engine/rhaibook/rust/derive-custom-type.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,227 @@
 | 
			
		||||
Auto-Generate API for Custom Type
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Warning"
 | 
			
		||||
 | 
			
		||||
This assumes that you have complete control of the type and can do whatever you want with it
 | 
			
		||||
(such as putting attributes on fields).
 | 
			
		||||
 | 
			
		||||
In particular, the type must be defined within the current crate.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
To register a type and its API for use with an [`Engine`], the simplest method is via the [`CustomType`] trait.
 | 
			
		||||
 | 
			
		||||
A custom derive macro is provided to auto-implement [`CustomType`] on any `struct` type,
 | 
			
		||||
which exposes all the type's fields to an [`Engine`] all at once.
 | 
			
		||||
 | 
			
		||||
It is as simple as adding `#[derive(CustomType)]` to the type definition.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{CustomType, TypeBuilder};    // <- necessary imports
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, CustomType)]            // <- auto-implement 'CustomType'
 | 
			
		||||
pub struct Vec3 {                       //    for normal structs
 | 
			
		||||
    pub x: i64,
 | 
			
		||||
    pub y: i64,
 | 
			
		||||
    pub z: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, CustomType)]            // <- auto-implement 'CustomType'
 | 
			
		||||
pub struct ABC(i64, bool, String);      //    for tuple structs
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Register the custom types!
 | 
			
		||||
engine.build_type::<Vec3>()
 | 
			
		||||
      .build_type::<ABC>();
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Custom Attribute Options
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
The `rhai_type` attribute, with options, can be added to the fields of the type to customize the auto-generated API.
 | 
			
		||||
 | 
			
		||||
|   Option   | Applies to  |       Value       | Description                                                                                                              |
 | 
			
		||||
| :--------: | :---------: | :---------------: | ------------------------------------------------------------------------------------------------------------------------ |
 | 
			
		||||
|   `name`   | type, field | string expression | use this name instead of the type/field name.                                                                            |
 | 
			
		||||
|   `skip`   |    field    |      _none_       | skip this field; cannot be used with any other attribute.                                                                |
 | 
			
		||||
| `readonly` |    field    |      _none_       | only auto-generate getter, no setter; cannot be used with `set`.                                                         |
 | 
			
		||||
|   `get`    |    field    |   function path   | use this getter function (with `&self`) instead of the auto-generated getter; if `get_mut` is also set, this is ignored. |
 | 
			
		||||
| `get_mut`  |    field    |   function path   | use this getter function (with `&mut self`) instead of the auto-generated getter.                                        |
 | 
			
		||||
| `set`      |    field    |   function path   | use this setter function instead of the auto-generated setter; cannot be used with `readonly`.                           |
 | 
			
		||||
| `extra`    |    type     |   function path   | call this function after building the type to add additional APIs                                                        |
 | 
			
		||||
 | 
			
		||||
### Function signatures
 | 
			
		||||
 | 
			
		||||
The signature of the function for `get` is:
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> Fn(&T) -> V
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
The signature of the function for `get_mut` is:
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> Fn(&mut T) -> V
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
The signature of the function for `set` is:
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> Fn(&mut T, V)
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
The signature of the function for `extra` is:
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> Fn(&mut TypeBuilder<T>)
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
### Example
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{CustomType, TypeBuilder};    // <- necessary imports
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
#[derive(CustomType)]                   // <- auto-implement 'CustomType'
 | 
			
		||||
pub struct ABC(
 | 
			
		||||
    #[rhai_type(skip)]                  // <- 'field0' not included
 | 
			
		||||
    i64,
 | 
			
		||||
 | 
			
		||||
    #[rhai_type(readonly)]              // <- only auto getter, no setter for 'field1'
 | 
			
		||||
    i64,
 | 
			
		||||
    
 | 
			
		||||
    #[rhai_type(name = "flag")]         // <- override property name for 'field2'
 | 
			
		||||
    bool,
 | 
			
		||||
    
 | 
			
		||||
    String                              // <- auto getter/setter for 'field3'
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
#[derive(Default, Clone)]
 | 
			
		||||
#[derive(CustomType)]                   // <- auto-implement 'CustomType'
 | 
			
		||||
#[rhai_type(name = "MyFoo", extra = Self::build_extra)] // <- call this type 'MyFoo' and use 'build_extra' to add additional APIs
 | 
			
		||||
pub struct Foo {
 | 
			
		||||
    #[rhai_type(skip)]                  // <- field not included
 | 
			
		||||
    dummy: i64,
 | 
			
		||||
 | 
			
		||||
    #[rhai_type(readonly)]              // <- only auto getter, no setter for 'bar'
 | 
			
		||||
    bar: i64,
 | 
			
		||||
 | 
			
		||||
    #[rhai_type(name = "flag")]         // <- override property name
 | 
			
		||||
    baz: bool,                          // <- auto getter/setter for 'baz'
 | 
			
		||||
 | 
			
		||||
    #[rhai_type(get = Self::qux)]       // <- call custom getter (with '&self') for 'qux'
 | 
			
		||||
    qux: char,                          // <- auto setter for 'qux'
 | 
			
		||||
 | 
			
		||||
    #[rhai_type(set = Self::set_hello)] // <- call custom setter for 'hello'
 | 
			
		||||
    hello: String                       // <- auto getter for 'hello'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Foo {
 | 
			
		||||
    /// Regular field getter function with `&self`
 | 
			
		||||
    pub fn qux(&self) -> char {
 | 
			
		||||
        self.qux
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Special setter implementation for `hello`
 | 
			
		||||
    pub fn set_hello(&mut self, value: String) {
 | 
			
		||||
        self.hello = if self.baz {
 | 
			
		||||
            let mut s = self.hello.clone();
 | 
			
		||||
            s.push_str(&value);
 | 
			
		||||
            for _ in 0..self.bar { s.push('!'); }
 | 
			
		||||
            s
 | 
			
		||||
        } else {
 | 
			
		||||
            value
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Additional APIs
 | 
			
		||||
    fn build_extra(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
        // Register constructor function
 | 
			
		||||
        builder.with_fn("new_foo", || Self::default());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, Eq, PartialEq, CustomType)]
 | 
			
		||||
#[rhai_fn(extra = vec3_build_extra)]
 | 
			
		||||
pub struct Vec3 {
 | 
			
		||||
    #[rhai_type(get = Self::x, set = Self::set_x)]
 | 
			
		||||
    x: i64,
 | 
			
		||||
    #[rhai_type(get = Self::y, set = Self::set_y)]
 | 
			
		||||
    y: i64,
 | 
			
		||||
    #[rhai_type(get = Self::z, set = Self::set_z)]
 | 
			
		||||
    z: i64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Vec3 {
 | 
			
		||||
    fn new(x: i64, y: i64, z: i64) -> Self { Self { x, y, z } }
 | 
			
		||||
    fn x(&self) -> i64 { self.x }
 | 
			
		||||
    fn set_x(&mut self, x: i64) { self.x = x }
 | 
			
		||||
    fn y(&self) -> i64 { self.y }
 | 
			
		||||
    fn set_y(&mut self, y: i64) { self.y = y }
 | 
			
		||||
    fn z(&self) -> i64 { self.z }
 | 
			
		||||
    fn set_z(&mut self, z: i64) { self.z = z }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn vec3_build_extra(builder: &mut TypeBuilder<Self>) {
 | 
			
		||||
    // Register constructor function
 | 
			
		||||
    builder.with_fn("Vec3", Self::new);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish question "TL;DR – The above is equivalent to this..."
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
impl CustomType for ABC {
 | 
			
		||||
    fn build(mut builder: TypeBuilder<Self>)
 | 
			
		||||
    {
 | 
			
		||||
        builder.with_name("ABC");
 | 
			
		||||
        builder.with_get("field1", |obj: &mut Self| obj.1.clone());
 | 
			
		||||
        builder.with_get_set("flag",
 | 
			
		||||
            |obj: &mut Self| obj.2.clone(),
 | 
			
		||||
            |obj: &mut Self, val| obj.2 = val
 | 
			
		||||
        );
 | 
			
		||||
        builder.with_get_set("field3",
 | 
			
		||||
            |obj: &mut Self| obj.3.clone(),
 | 
			
		||||
            |obj: &mut Self, val| obj.3 = val
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CustomType for Foo {
 | 
			
		||||
    fn build(mut builder: TypeBuilder<Self>)
 | 
			
		||||
    {
 | 
			
		||||
        builder.with_name("MyFoo");
 | 
			
		||||
        builder.with_get("bar", |obj: &mut Self| obj.bar.clone());
 | 
			
		||||
        builder.with_get_set("flag",
 | 
			
		||||
            |obj: &mut Self| obj.baz.clone(),
 | 
			
		||||
            |obj: &mut Self, val| obj.baz = val
 | 
			
		||||
        );
 | 
			
		||||
        builder.with_get_set("qux",
 | 
			
		||||
            |obj: &Self| Self::qux(&*obj)),
 | 
			
		||||
            |obj: &mut Self, val| obj.qux = val
 | 
			
		||||
        )
 | 
			
		||||
        builder.with_get_set("hello",
 | 
			
		||||
            |obj: &mut Self| obj.hello.clone(),
 | 
			
		||||
            Self::set_hello
 | 
			
		||||
        );
 | 
			
		||||
        Self::build_extra(&mut builder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CustomType for Vec3 {
 | 
			
		||||
    fn build(mut builder: TypeBuilder<Self>)
 | 
			
		||||
    {
 | 
			
		||||
        builder.with_name("Vec3");
 | 
			
		||||
        builder.with_get_set("x", |obj: &mut Self| Self::x(&*obj), Self::set_x);
 | 
			
		||||
        builder.with_get_set("y", |obj: &mut Self| Self::y(&*obj), Self::set_y);
 | 
			
		||||
        builder.with_get_set("z", |obj: &mut Self| Self::z(&*obj), Self::set_z);
 | 
			
		||||
        vec3_build_extra(&mut builder);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										12
									
								
								_archive/rhai_engine/rhaibook/rust/disable-custom.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								_archive/rhai_engine/rhaibook/rust/disable-custom.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,12 @@
 | 
			
		||||
Disable Custom Types
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
The [`no_object`] feature disables support for [custom types] including:
 | 
			
		||||
 | 
			
		||||
* [_method-style_]({{rootUrl}}/rust/methods.md}}) function calls (e.g. `obj.method()`),
 | 
			
		||||
 | 
			
		||||
* [object maps] and the [`Map`] type,
 | 
			
		||||
 | 
			
		||||
* the `register_get`, `register_set` and `register_get_set` APIs for [`Engine`]
 | 
			
		||||
							
								
								
									
										193
									
								
								_archive/rhai_engine/rhaibook/rust/dynamic-args.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								_archive/rhai_engine/rhaibook/rust/dynamic-args.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
`Dynamic` Parameters in Rust Functions
 | 
			
		||||
======================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
It is possible for Rust functions to contain parameters of type [`Dynamic`].
 | 
			
		||||
 | 
			
		||||
A [`Dynamic`] value can hold any clonable type.
 | 
			
		||||
 | 
			
		||||
```admonish question.small "Trivia"
 | 
			
		||||
 | 
			
		||||
The `push` method of an [array] is implemented as follows (minus code for [safety] protection
 | 
			
		||||
against [over-sized arrays][maximum size of arrays]), allowing the function to be called with
 | 
			
		||||
all item types.
 | 
			
		||||
 | 
			
		||||
~~~rust
 | 
			
		||||
// 'item: Dynamic' matches all data types
 | 
			
		||||
fn push(array: &mut Array, item: Dynamic) {
 | 
			
		||||
    array.push(item);
 | 
			
		||||
}
 | 
			
		||||
~~~
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Precedence
 | 
			
		||||
----------
 | 
			
		||||
 | 
			
		||||
Any parameter in a registered Rust function with a specific type has higher precedence over
 | 
			
		||||
[`Dynamic`], so it is important to understand which _version_ of a function will be used.
 | 
			
		||||
 | 
			
		||||
Parameter matching starts from the left to the right.
 | 
			
		||||
Candidate functions will be matched in order of parameter types.
 | 
			
		||||
 | 
			
		||||
Therefore, always leave [`Dynamic`] parameters (up to 16, see below) as far to the right as possible.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Dynamic};
 | 
			
		||||
 | 
			
		||||
// Different versions of the same function 'foo'
 | 
			
		||||
// will be matched in the following order.
 | 
			
		||||
 | 
			
		||||
fn foo1(x: i64, y: &str, z: bool) { }
 | 
			
		||||
 | 
			
		||||
fn foo2(x: i64, y: &str, z: Dynamic) { }
 | 
			
		||||
 | 
			
		||||
fn foo3(x: i64, y: Dynamic, z: bool) { }
 | 
			
		||||
 | 
			
		||||
fn foo4(x: i64, y: Dynamic, z: Dynamic) { }
 | 
			
		||||
 | 
			
		||||
fn foo5(x: Dynamic, y: &str, z: bool) { }
 | 
			
		||||
 | 
			
		||||
fn foo6(x: Dynamic, y: &str, z: Dynamic) { }
 | 
			
		||||
 | 
			
		||||
fn foo7(x: Dynamic, y: Dynamic, z: bool) { }
 | 
			
		||||
 | 
			
		||||
fn foo8(x: Dynamic, y: Dynamic, z: Dynamic) { }
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Register all functions under the same name (order does not matter)
 | 
			
		||||
 | 
			
		||||
engine.register_fn("foo", foo5)
 | 
			
		||||
      .register_fn("foo", foo7)
 | 
			
		||||
      .register_fn("foo", foo2)
 | 
			
		||||
      .register_fn("foo", foo8)
 | 
			
		||||
      .register_fn("foo", foo1)
 | 
			
		||||
      .register_fn("foo", foo3)
 | 
			
		||||
      .register_fn("foo", foo6)
 | 
			
		||||
      .register_fn("foo", foo4);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish warning "Only the right-most 16 parameters can be `Dynamic`"
 | 
			
		||||
 | 
			
		||||
The number of parameter permutations goes up exponentially, and therefore there is a realistic limit
 | 
			
		||||
of 16 parameters allowed to be [`Dynamic`], counting from the _right-most side_.
 | 
			
		||||
 | 
			
		||||
For example, Rhai will not find the following function – Oh! and those 16 parameters to the right
 | 
			
		||||
certainly have nothing to do with it!
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The 'd' parameter counts 17th from the right!
 | 
			
		||||
fn weird(a: i64, d: Dynamic, x1: i64, x2: i64, x3: i64, x4: i64,
 | 
			
		||||
                             x5: i64, x6: i64, x7: i64, x8: i64,
 | 
			
		||||
                             x9: i64, x10: i64, x11: i64, x12: i64,
 | 
			
		||||
                             x13: i64, x14: i64, x15: i64, x16: i64) {
 | 
			
		||||
 | 
			
		||||
    // ... do something unspeakably evil with all those parameters ...
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
TL;DR
 | 
			
		||||
-----
 | 
			
		||||
 | 
			
		||||
```admonish question "How is this implemented?"
 | 
			
		||||
 | 
			
		||||
#### Hash lookup
 | 
			
		||||
 | 
			
		||||
Since functions in Rhai can be [overloaded][function overloading], Rhai uses a single _hash_ number
 | 
			
		||||
to quickly lookup the actual function, based on argument types.
 | 
			
		||||
 | 
			
		||||
For each function call, a hash is calculated from:
 | 
			
		||||
 | 
			
		||||
1. the function's [namespace][function namespace], if any,
 | 
			
		||||
2. the function's name,
 | 
			
		||||
3. number of arguments (its _arity_),
 | 
			
		||||
4. unique ID of the type of each argument, if any.
 | 
			
		||||
 | 
			
		||||
The correct function is then obtained via a simple hash lookup.
 | 
			
		||||
 | 
			
		||||
#### Limitations
 | 
			
		||||
 | 
			
		||||
This method is _fast_, but at the expense of flexibility (such as multiple argument types that must
 | 
			
		||||
map to a single version).  That is because each type has a different ID, and thus they calculate to
 | 
			
		||||
different hash numbers.
 | 
			
		||||
 | 
			
		||||
This is the reason why [generic functions](generic.md) must be expanded into concrete types.
 | 
			
		||||
 | 
			
		||||
The type ID of [`Dynamic`] is different from any other type, but it must match all types seamlessly.
 | 
			
		||||
Needless to say, this creates a slight problem.
 | 
			
		||||
 | 
			
		||||
#### Trying combinations
 | 
			
		||||
 | 
			
		||||
If the combined hash calculated from the actual argument type ID's is not found, then the [`Engine`]
 | 
			
		||||
calculates hashes for different _combinations_ of argument types and [`Dynamic`], systematically
 | 
			
		||||
replacing different arguments with [`Dynamic`] _starting from the right-most parameter_.
 | 
			
		||||
 | 
			
		||||
Thus, assuming a three-argument function call:
 | 
			
		||||
 | 
			
		||||
~~~rust
 | 
			
		||||
foo(42, "hello", true);
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
The following hashes will be calculated, in order.
 | 
			
		||||
They will be _all different_.
 | 
			
		||||
 | 
			
		||||
| Order | Hash calculation method                             |
 | 
			
		||||
| :---: | --------------------------------------------------- |
 | 
			
		||||
|   1   | `foo` + 3 + `i64` + `string` + `bool`               |
 | 
			
		||||
|   2   | `foo` + 3 + `i64` + `string` + [`Dynamic`]          |
 | 
			
		||||
|   3   | `foo` + 3 + `i64` + [`Dynamic`] + `bool`            |
 | 
			
		||||
|   4   | `foo` + 3 + `i64` + [`Dynamic`] + [`Dynamic`]       |
 | 
			
		||||
|   5   | `foo` + 3 + [`Dynamic`] + `string` + `bool`         |
 | 
			
		||||
|   6   | `foo` + 3 + [`Dynamic`] + `string` + [`Dynamic`]    |
 | 
			
		||||
|   7   | `foo` + 3 + [`Dynamic`] + [`Dynamic`] + `bool`      |
 | 
			
		||||
|   8   | `foo` + 3 + [`Dynamic`] + [`Dynamic`] + [`Dynamic`] |
 | 
			
		||||
 | 
			
		||||
Therefore, the version with all the correct parameter types will always be found first if it exists.
 | 
			
		||||
 | 
			
		||||
At soon as a hash is found, the process stops.
 | 
			
		||||
 | 
			
		||||
Otherwise, it goes on for up to 16 arguments, or at most 65,536 tries.
 | 
			
		||||
That's where the 16 parameters limit comes from.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish question "What?! It calculates 65,536 hashes for each function call???!!!"
 | 
			
		||||
 | 
			
		||||
Of course not. Don't be silly.
 | 
			
		||||
 | 
			
		||||
#### Not every function has 16 parameters
 | 
			
		||||
 | 
			
		||||
Studies have repeatedly shown that most functions accept few parameters, with the mean between
 | 
			
		||||
2-3 parameters per function.  Functions with more than 5 parameters are rare in normal code bases.
 | 
			
		||||
If at all, they are usually [closures] that _capture_ lots of external variables, bumping up the
 | 
			
		||||
parameter count; but [closures] are always script-defined and thus all parameters are already
 | 
			
		||||
[`Dynamic`].
 | 
			
		||||
 | 
			
		||||
In fact, you have a bigger problem if you write such a function that you need to call regularly.
 | 
			
		||||
It would be far more efficient to group those parameters into [object maps].
 | 
			
		||||
 | 
			
		||||
#### Caching to the rescue
 | 
			
		||||
 | 
			
		||||
Function hashes are _cached_, so this process only happens _once_, and only up to the number of
 | 
			
		||||
rounds for the correct function to be found.
 | 
			
		||||
 | 
			
		||||
If not, then yes, it will calculate up to 2<sup>_n_</sup> hashes where _n_ is the number of
 | 
			
		||||
arguments (up to 16). But again, this will only be done _once_ for that particular
 | 
			
		||||
combination of argument types.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish danger "But then... beware module functions"
 | 
			
		||||
 | 
			
		||||
The functions resolution _cache_ resides only in the [global namespace][function namespace].
 | 
			
		||||
This is a limitation.
 | 
			
		||||
 | 
			
		||||
Therefore, calls to functions in an [`import`]ed [module] (i.e. _qualified_ with
 | 
			
		||||
a [namespace][function namespace] path) do not have the benefit of a cache.
 | 
			
		||||
 | 
			
		||||
Thus, up to 2<sup>_n_</sup> hashes are calculated during _every_ function call.
 | 
			
		||||
This is unlikely to cause a performance issue since most functions accept only a few parameters.
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										94
									
								
								_archive/rhai_engine/rhaibook/rust/dynamic-return.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								_archive/rhai_engine/rhaibook/rust/dynamic-return.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,94 @@
 | 
			
		||||
`Dynamic` Return Value
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Rhai supports registering functions that return [`Dynamic`].
 | 
			
		||||
 | 
			
		||||
A [`Dynamic`] value can hold any clonable type.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Dynamic};
 | 
			
		||||
 | 
			
		||||
// The 'Dynamic' return type allows this function to
 | 
			
		||||
// return values of any supported type!
 | 
			
		||||
fn get_info(bag: &mut PropertyBag, key: &str) -> Dynamic {
 | 
			
		||||
    if let Some(prop_type) = bag.get_type(key) {
 | 
			
		||||
        match prop_type {
 | 
			
		||||
            // Use '.into()' for standard types
 | 
			
		||||
            "string" => bag.get::<&str>(key).into(),
 | 
			
		||||
            "int" => bag.get::<i64>(key).into(),
 | 
			
		||||
            "bool" => bag.get::<bool>(key).into(),
 | 
			
		||||
                            :
 | 
			
		||||
                            :
 | 
			
		||||
            // Use 'Dynamic::from' for custom types
 | 
			
		||||
            "bag" => Dynamic::from(bag.get::<PropertyBag>(key))
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        // Return () upon error
 | 
			
		||||
        Dynamic::UNIT
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("get_info", get_info);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Create a `Dynamic`"
 | 
			
		||||
 | 
			
		||||
To create a [`Dynamic`] value, use `Dynamic::from`.
 | 
			
		||||
 | 
			
		||||
[Standard types] in Rhai can also use `.into()`.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::Dynamic;
 | 
			
		||||
 | 
			
		||||
let obj = TestStruct::new();
 | 
			
		||||
 | 
			
		||||
let x = Dynamic::from(obj);
 | 
			
		||||
 | 
			
		||||
// '.into()' works for standard types
 | 
			
		||||
 | 
			
		||||
let x = 42_i64.into();
 | 
			
		||||
 | 
			
		||||
let y = "hello!".into();
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Alternative to fallible functions"
 | 
			
		||||
 | 
			
		||||
Instead of registering a [fallible function], it is usually more idiomatic to leverage the _dynamic_
 | 
			
		||||
nature of Rhai and simply return [`()`] upon error.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Dynamic};
 | 
			
		||||
 | 
			
		||||
// Function that may fail - return () upon failure
 | 
			
		||||
fn safe_divide(x: i64, y: i64) -> Dynamic {
 | 
			
		||||
    if y == 0 {
 | 
			
		||||
        // Return () to indicate an error if y is zero
 | 
			
		||||
        Dynamic::UNIT
 | 
			
		||||
    } else {
 | 
			
		||||
        // Use '.into()' to convert standard types to 'Dynamic'
 | 
			
		||||
        (x / y).into()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("divide", safe_divide);
 | 
			
		||||
 | 
			
		||||
// The following prints 'error!'
 | 
			
		||||
engine.run(r#"
 | 
			
		||||
    let result = divide(40, 0);
 | 
			
		||||
    
 | 
			
		||||
    if result == () {
 | 
			
		||||
        print("error!");
 | 
			
		||||
    } else {
 | 
			
		||||
        print(result);
 | 
			
		||||
    }
 | 
			
		||||
"#)?;
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										54
									
								
								_archive/rhai_engine/rhaibook/rust/fallible.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								_archive/rhai_engine/rhaibook/rust/fallible.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,54 @@
 | 
			
		||||
Register a Fallible Rust Function
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.side.wide "Tip: Consider `Dynamic`"
 | 
			
		||||
 | 
			
		||||
A lot of times it is not necessary to register fallible functions.
 | 
			
		||||
 | 
			
		||||
Simply have the function returns [`Dynamic`].
 | 
			
		||||
Upon error, return [`()`] which is idiomatic in Rhai.
 | 
			
		||||
 | 
			
		||||
See [here](dynamic-return.md) for more details.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
If a function is _fallible_ (i.e. it returns a `Result<_, _>`), it can also be registered with via
 | 
			
		||||
`Engine::register_fn`.
 | 
			
		||||
 | 
			
		||||
The function must return `Result<T, Box<EvalAltResult>>` where `T` is any clonable type.
 | 
			
		||||
 | 
			
		||||
In other words, the error type _must_ be `Box<EvalAltResult>`.  It is `Box`ed in order to reduce
 | 
			
		||||
the size of the `Result` type since the error path is rarely hit.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
// Function that may fail - the error type must be 'Box<EvalAltResult>'
 | 
			
		||||
fn safe_divide(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> {
 | 
			
		||||
    if y == 0 {
 | 
			
		||||
        // Return an error if y is zero
 | 
			
		||||
        Err("Division by zero!".into())         // shortcut to create Box<EvalAltResult::ErrorRuntime>
 | 
			
		||||
    } else {
 | 
			
		||||
        Ok(x / y)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("divide", safe_divide);
 | 
			
		||||
 | 
			
		||||
if let Err(error) = engine.eval::<i64>("divide(40, 0)") {
 | 
			
		||||
    println!("Error: {error:?}");               // prints ErrorRuntime("Division by zero detected!", (1, 1)")
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Create a `Box<EvalAltResult>`"
 | 
			
		||||
 | 
			
		||||
`Box<EvalAltResult>` implements `From<&str>` and `From<String>` etc.
 | 
			
		||||
and the error text gets converted into `Box<EvalAltResult::ErrorRuntime>`.
 | 
			
		||||
 | 
			
		||||
The error values are `Box`-ed in order to reduce memory footprint of the error path,
 | 
			
		||||
which should be hit rarely.
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										20
									
								
								_archive/rhai_engine/rhaibook/rust/functions-metadata.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								_archive/rhai_engine/rhaibook/rust/functions-metadata.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
Get Scripted Functions  Metadata from AST
 | 
			
		||||
=========================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Use [`AST::iter_functions`](https://docs.rs/rhai/latest/rhai/struct.AST.html#method.iter_functions)
 | 
			
		||||
to iterate through all the script-defined [functions] in an [`AST`].
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`ScriptFnMetadata`
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
The type returned from the iterator is `ScriptFnMetadata` with the following fields:
 | 
			
		||||
 | 
			
		||||
| Field      |   Requires   |    Type     | Description                                                           |
 | 
			
		||||
| ---------- | :----------: | :---------: | --------------------------------------------------------------------- |
 | 
			
		||||
| `name`     |              |   `&str`    | Name of [function]                                                    |
 | 
			
		||||
| `params`   |              | `Vec<&str>` | Number of parameters                                                  |
 | 
			
		||||
| `access`   |              | `FnAccess`  | • `FnAccess::Public` (public)<br/>• `FnAccess::Private` ([`private`]) |
 | 
			
		||||
| `comments` | [`metadata`] | `Vec<&str>` | [Doc-comments], if any, one per line                                  |
 | 
			
		||||
							
								
								
									
										151
									
								
								_archive/rhai_engine/rhaibook/rust/functions.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								_archive/rhai_engine/rhaibook/rust/functions.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
Register a Rust Function for Use in Rhai Scripts
 | 
			
		||||
================================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Rhai's scripting engine is very lightweight.  It gets most of its abilities from functions.
 | 
			
		||||
 | 
			
		||||
To call these functions, they need to be _registered_ via `Engine::register_fn`.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Dynamic, Engine, ImmutableString};
 | 
			
		||||
 | 
			
		||||
// Normal function that returns a standard type
 | 
			
		||||
// Remember to use 'ImmutableString' and not 'String'
 | 
			
		||||
fn add_len(x: i64, s: ImmutableString) -> i64 {
 | 
			
		||||
    x + s.len()
 | 
			
		||||
}
 | 
			
		||||
// Alternatively, '&str' maps directly to 'ImmutableString'
 | 
			
		||||
fn add_len_count(x: i64, s: &str, c: i64) -> i64 {
 | 
			
		||||
    x + s.len() * c
 | 
			
		||||
}
 | 
			
		||||
// Function that returns a 'Dynamic' value
 | 
			
		||||
fn get_any_value() -> Dynamic {
 | 
			
		||||
    42_i64.into()                       // standard types can use '.into()'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Notice that all three functions are overloaded into the same name with
 | 
			
		||||
// different number of parameters and/or parameter types.
 | 
			
		||||
engine.register_fn("add", add_len)
 | 
			
		||||
      .register_fn("add", add_len_count)
 | 
			
		||||
      .register_fn("add", get_any_value)
 | 
			
		||||
      .register_fn("inc", |x: i64| {    // closure is also OK!
 | 
			
		||||
          x + 1
 | 
			
		||||
      })
 | 
			
		||||
      .register_fn("log", |label: &str, x: i64| {
 | 
			
		||||
          println!("{label} = {x}");
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>(r#"add(40, "xx")"#)?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");           // prints 42
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>(r#"add(40, "x", 2)"#)?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");           // prints 42
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>("add()")?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");           // prints 42
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>("inc(41)")?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");           // prints 42
 | 
			
		||||
 | 
			
		||||
engine.run(r#"log("value", 42)"#)?;     // prints "value = 42"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip "Tip: Use closures"
 | 
			
		||||
 | 
			
		||||
It is common for short functions to be registered via a _closure_.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
┌──────┐
 | 
			
		||||
│ Rust │
 | 
			
		||||
└──────┘
 | 
			
		||||
 | 
			
		||||
engine.register_fn("foo", |x: i64, y: i64| x * 2 + y * 3);
 | 
			
		||||
//                            ^^^     ^^^
 | 
			
		||||
// Usually parameter types need to be specified
 | 
			
		||||
 | 
			
		||||
engine.register_fn("bar", |x: i64| -> Result<_, Box<EvalAltResult>> { x * 2 });
 | 
			
		||||
//                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 | 
			
		||||
// For fallible closures, the return ERROR type may need to be specified
 | 
			
		||||
 | 
			
		||||
┌─────────────┐
 | 
			
		||||
│ Rhai script │
 | 
			
		||||
└─────────────┘
 | 
			
		||||
 | 
			
		||||
foo(42, 100);       // <- 42 * 2 + 100 * 3
 | 
			
		||||
```
 | 
			
		||||
#### Interact with external environment
 | 
			
		||||
 | 
			
		||||
An additional benefit to using closures is that they can capture external variables.
 | 
			
		||||
 | 
			
		||||
For example, capturing a type wrapped in shared mutability (e.g. `Rc<RefCell<T>>`)
 | 
			
		||||
allows a script to interact with the external environment through that shared type.
 | 
			
		||||
 | 
			
		||||
See also: [Control Layer]({{rootUrl}}/patterns/control.md).
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
┌──────┐
 | 
			
		||||
│ Rust │
 | 
			
		||||
└──────┘
 | 
			
		||||
 | 
			
		||||
/// A type that encapsulates some behavior.
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
struct TestStruct { ... }
 | 
			
		||||
 | 
			
		||||
impl TestSTruct {
 | 
			
		||||
    /// Some action defined on that type.
 | 
			
		||||
    pub fn do_foo(&self, x: i64, y: bool) {
 | 
			
		||||
        // ... do something drastic with x and y
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Wrapped in shared mutability: Rc<RefCell<TestStruct>>.
 | 
			
		||||
let shared_obj = Rc::new(RefCell::new(TestStruct::new()));
 | 
			
		||||
 | 
			
		||||
/// Clone the shared reference and move it into the closure.
 | 
			
		||||
let embedded_obj = shared.clone();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("foo", move |x: i64, y: bool| {
 | 
			
		||||
//                        ^^^^ 'embedded_obj' is captured into the closure
 | 
			
		||||
 | 
			
		||||
    embedded_obj.borrow().do_foo(x, y);
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
┌─────────────┐
 | 
			
		||||
│ Rhai script │
 | 
			
		||||
└─────────────┘
 | 
			
		||||
 | 
			
		||||
foo(42, true);      // <- equivalent to: shared_obj.borrow().do_foo(42, true);
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
~~~admonish warning "Warning: Don't touch those generic parameters"
 | 
			
		||||
 | 
			
		||||
Rhai uses an intricate system of traits (in particular `RhaiNativeFunc`) with many generic parameters to ensure
 | 
			
		||||
an intuitive and smooth developer experience that _just works_.
 | 
			
		||||
 | 
			
		||||
Because of this, it is not recommended to touch those generic parameters directly.  These generic parameters may change
 | 
			
		||||
liberally in future versions of Rhai. In most situations they are automatically inferred by the compiler.
 | 
			
		||||
 | 
			
		||||
In the cases where the compiler fail to infer types when registering a _closure_, (usually with the _error_ type
 | 
			
		||||
of a [fallible function]), manually declare the parameter and/or return types.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The following fails to compile because the compiler does not know
 | 
			
		||||
// the return _error_ type of the closure.
 | 
			
		||||
// It knows the return type, which is 'Result<i64, E>', but 'E' is not known.
 | 
			
		||||
engine.register_fn("foo", |x: i64| Ok(x));
 | 
			
		||||
 | 
			
		||||
// Don't do this...
 | 
			
		||||
engine.register_fn::<_, 1, false, i64, Box<EvalAltResult>>("foo", |x: i64| Ok(x));
 | 
			
		||||
 | 
			
		||||
// Do this...
 | 
			
		||||
engine.register_fn("foo", |x: i64| -> Result<i64, Box<EvalAltResult>> { Ok(x) });
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										36
									
								
								_archive/rhai_engine/rhaibook/rust/generic.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								_archive/rhai_engine/rhaibook/rust/generic.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,36 @@
 | 
			
		||||
Register a Generic Rust Function
 | 
			
		||||
================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "No monomorphization"
 | 
			
		||||
 | 
			
		||||
Due to its dynamic nature, Rhai cannot monomorphize generic functions automatically.
 | 
			
		||||
 | 
			
		||||
Monomorphization of generic functions must be performed manually.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Rust generic functions can be used in Rhai, but separate instances for each concrete type must be
 | 
			
		||||
registered separately.
 | 
			
		||||
 | 
			
		||||
This essentially _overloads_ the function with different parameter types as Rhai does not natively
 | 
			
		||||
support generics but Rhai does support _[function overloading]_.
 | 
			
		||||
 | 
			
		||||
The example below shows how to register multiple functions (or, in this case, multiple overloaded
 | 
			
		||||
versions of the same function) under the same name.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use std::fmt::Display;
 | 
			
		||||
 | 
			
		||||
use rhai::Engine;
 | 
			
		||||
 | 
			
		||||
fn show_it<T: Display>(x: &mut T) {
 | 
			
		||||
    println!("put up a good show: {x}!");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("print", show_it::<i64>)
 | 
			
		||||
      .register_fn("print", show_it::<bool>)
 | 
			
		||||
      .register_fn("print", show_it::<ImmutableString>);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										168
									
								
								_archive/rhai_engine/rhaibook/rust/getters-setters.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										168
									
								
								_archive/rhai_engine/rhaibook/rust/getters-setters.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,168 @@
 | 
			
		||||
Custom Type Property Getters and Setters
 | 
			
		||||
========================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish warning.side.wide "Cannot override object maps"
 | 
			
		||||
 | 
			
		||||
Property getters and setters are intended for [custom types].
 | 
			
		||||
 | 
			
		||||
Any getter or setter function registered for [object maps] is simply _ignored_.
 | 
			
		||||
 | 
			
		||||
Get/set syntax on [object maps] is interpreted as access to properties.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A [custom type] can also expose properties by registering `get` and/or `set` functions.
 | 
			
		||||
 | 
			
		||||
Properties can be accessed in a Rust-like syntax:
 | 
			
		||||
 | 
			
		||||
> _object_ `.` _property_
 | 
			
		||||
>
 | 
			
		||||
> _object_ `.` _property_ `=` _value_ `;`
 | 
			
		||||
 | 
			
		||||
The [_Elvis operator_](https://en.wikipedia.org/wiki/Elvis_operator) can be used to short-circuit
 | 
			
		||||
processing if the object itself is [`()`]:
 | 
			
		||||
 | 
			
		||||
> `// returns () if object is ()`  
 | 
			
		||||
> _object_ `?.` _property_
 | 
			
		||||
>
 | 
			
		||||
> `// no action if object is ()`  
 | 
			
		||||
> _object_ `?.` _property_ `=` _value_ `;`
 | 
			
		||||
 | 
			
		||||
Property getter and setter functions are called behind the scene.
 | 
			
		||||
They each take a `&mut` reference to the first parameter.
 | 
			
		||||
 | 
			
		||||
Getters and setters are disabled under the [`no_object`] feature.
 | 
			
		||||
 | 
			
		||||
<section></section>
 | 
			
		||||
 | 
			
		||||
| `Engine` API       | Function signature(s)<br/>(`T: Clone` = custom type,<br/>`V: Clone` = data type) |        Can mutate `T`?         |
 | 
			
		||||
| ------------------ | -------------------------------------------------------------------------------- | :----------------------------: |
 | 
			
		||||
| `register_get`     | `Fn(&mut T) -> V`                                                                |      yes, but not advised      |
 | 
			
		||||
| `register_set`     | `Fn(&mut T, V)`                                                                  |              yes               |
 | 
			
		||||
| `register_get_set` | getter: `Fn(&mut T) -> V`</br>setter: `Fn(&mut T, V)`                            | yes, but not advised in getter |
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "No support for references"
 | 
			
		||||
 | 
			
		||||
Rhai does NOT support normal references (i.e. `&T`) as parameters.
 | 
			
		||||
All references must be mutable (i.e. `&mut T`).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Getters must be pure"
 | 
			
		||||
 | 
			
		||||
By convention, property getters are assumed to be _pure_, meaning that they are not supposed to
 | 
			
		||||
mutate the [custom type], although there is nothing that prevents this mutation in Rust.
 | 
			
		||||
 | 
			
		||||
Even though a property getter function also takes `&mut` as the first parameter, Rhai assumes that
 | 
			
		||||
no data is changed when the function is called.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Examples
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct TestStruct {
 | 
			
		||||
    field: String
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TestStruct {
 | 
			
		||||
    // Remember &mut must be used even for getters.
 | 
			
		||||
    fn get_field(&mut self) -> String {
 | 
			
		||||
        // Property getters are assumed to be PURE, meaning they are
 | 
			
		||||
        // not supposed to mutate any data.
 | 
			
		||||
        self.field.clone()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn set_field(&mut self, new_val: String) {
 | 
			
		||||
        self.field = new_val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self { field: "hello, world!".to_string() }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_type::<TestStruct>()
 | 
			
		||||
      .register_get_set("xyz", TestStruct::get_field, TestStruct::set_field)
 | 
			
		||||
      .register_fn("new_ts", TestStruct::new);
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<String>(
 | 
			
		||||
r#"
 | 
			
		||||
    let a = new_ts();
 | 
			
		||||
    a.xyz = "42";
 | 
			
		||||
    a.xyz
 | 
			
		||||
"#)?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");                   // prints 42
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Fallback to Indexer
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
```admonish note.side "See also"
 | 
			
		||||
 | 
			
		||||
See [this section](indexer-prop-fallback.md) for details on an [indexer]
 | 
			
		||||
acting as fallback to properties.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If the getter/setter of a particular property is not defined, but an [indexer] is defined on the
 | 
			
		||||
[custom type] with [string] index, then the corresponding [indexer] will be called with the name of
 | 
			
		||||
the property as the index value.
 | 
			
		||||
 | 
			
		||||
In other words, [indexers] act as a _fallback_ to property getters/setters.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
a.foo           // if property getter for 'foo' doesn't exist...
 | 
			
		||||
 | 
			
		||||
a["foo"]        // an indexer (if any) is tried
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Implement a property bag"
 | 
			
		||||
 | 
			
		||||
This feature makes it very easy for [custom types] to act as _property bags_
 | 
			
		||||
(similar to an [object map]) which can add/remove properties at will.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Chaining Updates
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
It is possible to _chain_ property accesses and/or indexing (via [indexers]) together to modify a
 | 
			
		||||
particular property value at the end of the chain.
 | 
			
		||||
 | 
			
		||||
Rhai detects such modifications and updates the changed values all the way back up the chain.
 | 
			
		||||
 | 
			
		||||
In the end, the syntax works as expected by intuition, automatically and without special attention.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Assume a deeply-nested object...
 | 
			
		||||
let root = get_new_container_object();
 | 
			
		||||
 | 
			
		||||
root.prop1.sub["hello"].list[0].value = 42;
 | 
			
		||||
 | 
			
		||||
// The above is equivalent to:
 | 
			
		||||
 | 
			
		||||
// First getting all the intermediate values...
 | 
			
		||||
let prop1_value = root.prop1;                   // via property getter
 | 
			
		||||
let sub_value = prop1_value.sub;                // via property getter
 | 
			
		||||
let sub_value_item = sub_value["hello"];        // via index getter
 | 
			
		||||
let list_value = sub_value_item.list;           // via property getter
 | 
			
		||||
let list_item = list_value[0];                  // via index getter
 | 
			
		||||
 | 
			
		||||
list_item.value = 42;       // modify property value deep down the chain
 | 
			
		||||
 | 
			
		||||
// Propagate the changes back up the chain...
 | 
			
		||||
list_value[0] = list_item;                      // via index setter
 | 
			
		||||
sub_value_item.list = list_value;               // via property setter
 | 
			
		||||
sub_value["hello"] = sub_value_item;            // via index setter
 | 
			
		||||
prop1_value.sub = sub_value;                    // via property setter
 | 
			
		||||
root.prop1 = prop1_value;                       // via property setter
 | 
			
		||||
 | 
			
		||||
// The below prints 42...
 | 
			
		||||
print(root.prop1.sub["hello"].list[0].value);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										76
									
								
								_archive/rhai_engine/rhaibook/rust/immutable-string.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								_archive/rhai_engine/rhaibook/rust/immutable-string.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,76 @@
 | 
			
		||||
The `ImmutableString` Type
 | 
			
		||||
==========================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
~~~admonish question.side "Why `SmartString`?"
 | 
			
		||||
 | 
			
		||||
[`SmartString`] is used because many strings in scripts are short (fewer than 24 ASCII characters).
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
All [strings] in Rhai are implemented as `ImmutableString`, which is an alias to
 | 
			
		||||
`Rc<SmartString>` (or `Arc<SmartString>` under the [`sync`] feature).
 | 
			
		||||
 | 
			
		||||
An `ImmutableString` is immutable (i.e. never changes) and therefore can be shared among many users.
 | 
			
		||||
Cloning an `ImmutableString` is cheap since it only copies an immutable reference.
 | 
			
		||||
 | 
			
		||||
Modifying an `ImmutableString` causes it first to be cloned, and then the modification made to the copy.
 | 
			
		||||
Therefore, direct string modifications are expensive.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Avoid `String` Parameters
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
`ImmutableString` should be used in place of `String` for function parameters because using `String`
 | 
			
		||||
is very inefficient (the argument is cloned during every function call).
 | 
			
		||||
 | 
			
		||||
A alternative is to use `&str` which de-sugars to `ImmutableString`.
 | 
			
		||||
 | 
			
		||||
A function with the first parameter being `&mut String` does not match a string argument passed to it,
 | 
			
		||||
which has type `ImmutableString`.  In fact, `&mut String` is treated as an opaque [custom type].
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
fn slow(s: String) -> i64 { ... }               // string is cloned each call
 | 
			
		||||
 | 
			
		||||
fn fast1(s: ImmutableString) -> i64 { ... }     // cloning 'ImmutableString' is cheap
 | 
			
		||||
 | 
			
		||||
fn fast2(s: &str) -> i64 { ... }                // de-sugars to above
 | 
			
		||||
 | 
			
		||||
fn bad(s: &mut String) { ... }                  // '&mut String' will not match string values
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Differences from Rust Strings
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
Internally Rhai strings are stored as UTF-8 just like Rust (they _are_ Rust `String`s!),
 | 
			
		||||
but nevertheless there are major differences.
 | 
			
		||||
 | 
			
		||||
In Rhai a [string] is semantically the same as an array of Unicode characters and can be directly
 | 
			
		||||
indexed (unlike Rust).
 | 
			
		||||
 | 
			
		||||
This is similar to most other languages (e.g. JavaScript, C#) where strings are stored internally
 | 
			
		||||
not as UTF-8 but as arrays of UCS-16 or UCS-32.
 | 
			
		||||
 | 
			
		||||
Individual characters within a Rhai string can also be replaced just as if the string is an array of
 | 
			
		||||
Unicode characters.
 | 
			
		||||
 | 
			
		||||
In Rhai, there are also no separate concepts of `String` and `&str` (a string slice) as in Rust.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish warning "Performance considerations"
 | 
			
		||||
 | 
			
		||||
Although Rhai exposes a [string] as a simple array of [characters] which can be directly indexed to
 | 
			
		||||
get at a particular [character], such convenient syntax is an _illusion_.
 | 
			
		||||
 | 
			
		||||
Internally the [string] is still stored in UTF-8 (native Rust `String`s).
 | 
			
		||||
 | 
			
		||||
All indexing operations actually require walking through the entire UTF-8 string to find the offset
 | 
			
		||||
of the particular [character] position, and therefore is _much_ slower than the simple array
 | 
			
		||||
indexing for other scripting languages.
 | 
			
		||||
 | 
			
		||||
This implementation detail is hidden from the user but has a performance implication.
 | 
			
		||||
 | 
			
		||||
Avoid large scale [character]-based processing of [strings]; instead, build an actual [array] of
 | 
			
		||||
[characters] (via the `split()` method) which can then be manipulated efficiently.
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										11
									
								
								_archive/rhai_engine/rhaibook/rust/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								_archive/rhai_engine/rhaibook/rust/index.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,11 @@
 | 
			
		||||
Extend Rhai with Rust
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
{{#title Extend Rhai with Rust}}
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Most features and functionalities required by a Rhai script should actually be coded in Rust,
 | 
			
		||||
which leverages the superior native run-time speed.
 | 
			
		||||
 | 
			
		||||
This section discusses how to extend Rhai with functionalities written in Rust.
 | 
			
		||||
							
								
								
									
										101
									
								
								_archive/rhai_engine/rhaibook/rust/indexer-prop-fallback.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								_archive/rhai_engine/rhaibook/rust/indexer-prop-fallback.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,101 @@
 | 
			
		||||
Indexer as Property Access Fallback
 | 
			
		||||
===================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish tip.side "Tip: Property bag"
 | 
			
		||||
 | 
			
		||||
Such an [indexer] allows easy creation of _property bags_ (similar to [object maps])
 | 
			
		||||
which can dynamically add/remove properties.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
An [indexer] taking a [string] index is a special case – it acts as a _fallback_ to property
 | 
			
		||||
[getters/setters].
 | 
			
		||||
 | 
			
		||||
During a property access, if the appropriate property [getter/setter][getters/setters] is not
 | 
			
		||||
defined, an [indexer] is called and passed the string name of the property.
 | 
			
		||||
 | 
			
		||||
This is also extremely useful as a short-hand for [indexers], when the [string] keys conform to
 | 
			
		||||
property name syntax.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Assume 'obj' has an indexer defined with string parameters...
 | 
			
		||||
 | 
			
		||||
// Let's create a new key...
 | 
			
		||||
obj.hello_world = 42;
 | 
			
		||||
 | 
			
		||||
// The above is equivalent to this:
 | 
			
		||||
obj["hello_world"] = 42;
 | 
			
		||||
 | 
			
		||||
// You can write this...
 | 
			
		||||
let x = obj["hello_world"];
 | 
			
		||||
 | 
			
		||||
// but it is easier with this...
 | 
			
		||||
let x = obj.hello_world;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Swizzling"
 | 
			
		||||
 | 
			
		||||
Since an [indexer] can serve as a _fallback_ to [property access][getters/setters],
 | 
			
		||||
it is possible to implement [swizzling](https://en.wikipedia.org/wiki/Swizzling_(computer_graphics))
 | 
			
		||||
of properties for use with vector-like [custom types].
 | 
			
		||||
 | 
			
		||||
Such an [indexer] defined on a [custom type] (for instance, `Float4`) can inspect the property name,
 | 
			
		||||
construct a proper return value based on the swizzle pattern, and return it.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Assume 'v' is a 'Float4'
 | 
			
		||||
let r = v.w;        // -> v.w
 | 
			
		||||
let r = v.xx;       // -> Float2::new(v.x, v.x)
 | 
			
		||||
let r = v.yxz;      // -> Float3::new(v.y, v.x, v.z)
 | 
			
		||||
let r = v.xxzw;     // -> Float4::new(v.x, v.x, v.z, v.w)
 | 
			
		||||
let r = v.yyzzxx;   // error: property 'yyzzxx' not found
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Caveat – Reverse is NOT True
 | 
			
		||||
----------------------------------
 | 
			
		||||
 | 
			
		||||
The reverse, however, is not true – when an [indexer] fails or doesn't exist, the corresponding
 | 
			
		||||
property [getter/setter][getters/setters], if any, is not called.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
type MyType = HashMap<String, i64>;
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Define custom type, property getter and string indexers
 | 
			
		||||
engine.register_type::<MyType>()
 | 
			
		||||
      .register_fn("new_ts", || {
 | 
			
		||||
          let mut obj = MyType::new();
 | 
			
		||||
          obj.insert("foo".to_string(), 1);
 | 
			
		||||
          obj.insert("bar".to_string(), 42);
 | 
			
		||||
          obj.insert("baz".to_string(), 123);
 | 
			
		||||
          obj
 | 
			
		||||
      })
 | 
			
		||||
      // Property 'hello'
 | 
			
		||||
      .register_get("hello", |obj: &mut MyType| obj.len() as i64)
 | 
			
		||||
      // Index getter/setter
 | 
			
		||||
      .register_indexer_get(|obj: &mut MyType, prop: &str| -> Result<i64, Box<EvalAltResult>>
 | 
			
		||||
          obj.get(index).cloned().ok_or_else(|| "not found".into())
 | 
			
		||||
      ).register_indexer_set(|obj: &mut MyType, prop: &str, value: i64|
 | 
			
		||||
          obj.insert(prop.to_string(), value)
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
engine.run("let ts = new_ts(); print(ts.foo);");
 | 
			
		||||
//                                   ^^^^^^
 | 
			
		||||
//                 Calls ts["foo"] - getter for 'foo' does not exist
 | 
			
		||||
 | 
			
		||||
engine.run("let ts = new_ts(); print(ts.bar);");
 | 
			
		||||
//                                   ^^^^^^
 | 
			
		||||
//                 Calls ts["bar"] - getter for 'bar' does not exist
 | 
			
		||||
 | 
			
		||||
engine.run("let ts = new_ts(); ts.baz = 999;");
 | 
			
		||||
//                             ^^^^^^^^^^^^
 | 
			
		||||
//                 Calls ts["baz"] = 999 - setter for 'baz' does not exist
 | 
			
		||||
 | 
			
		||||
engine.run(r#"let ts = new_ts(); print(ts["hello"]);"#);
 | 
			
		||||
//                                     ^^^^^^^^^^^
 | 
			
		||||
//                 Error: Property getter for 'hello' not a fallback for indexer
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										197
									
								
								_archive/rhai_engine/rhaibook/rust/indexers.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										197
									
								
								_archive/rhai_engine/rhaibook/rust/indexers.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,197 @@
 | 
			
		||||
Custom Type Indexers
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
A [custom type] can also expose an _indexer_ by registering an indexer function.
 | 
			
		||||
 | 
			
		||||
A [custom type] with an indexer function defined can use the bracket notation to get/set a property
 | 
			
		||||
value at a particular index:
 | 
			
		||||
 | 
			
		||||
> _object_ `[` _index_ `]`
 | 
			
		||||
>
 | 
			
		||||
> _object_ `[` _index_ `]` `=` _value_ `;`
 | 
			
		||||
 | 
			
		||||
The [_Elvis notation_][elvis] is similar except that it returns [`()`] if the object itself is [`()`].
 | 
			
		||||
 | 
			
		||||
> `// returns () if object is ()`  
 | 
			
		||||
> _object_ `?[` _index_ `]`
 | 
			
		||||
>
 | 
			
		||||
> `// no action if object is ()`  
 | 
			
		||||
> _object_ `?[` _index_ `]` `=` _value_ `;`
 | 
			
		||||
 | 
			
		||||
Like property [getters/setters], indexers take a `&mut` reference to the first parameter.
 | 
			
		||||
 | 
			
		||||
They also take an additional parameter of any type that serves as the _index_ within brackets.
 | 
			
		||||
 | 
			
		||||
Indexers are disabled when the [`no_index`] and [`no_object`] features are used together.
 | 
			
		||||
 | 
			
		||||
| `Engine` API               | Function signature(s)<br/>(`T: Clone` = custom type,<br/>`X: Clone` = index type,<br/>`V: Clone` = data type) |        Can mutate `T`?         |
 | 
			
		||||
| -------------------------- | ------------------------------------------------------------------------------------------------------------- | :----------------------------: |
 | 
			
		||||
| `register_indexer_get`     | `Fn(&mut T, X) -> V`                                                                                          |      yes, but not advised      |
 | 
			
		||||
| `register_indexer_set`     | `Fn(&mut T, X, V)`                                                                                            |              yes               |
 | 
			
		||||
| `register_indexer_get_set` | getter: `Fn(&mut T, X) -> V`<br/>setter: `Fn(&mut T, X, V)`                                                   | yes, but not advised in getter |
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "No support for references"
 | 
			
		||||
 | 
			
		||||
Rhai does NOT support normal references (i.e. `&T`) as parameters.
 | 
			
		||||
All references must be mutable (i.e. `&mut T`).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Getters must be pure"
 | 
			
		||||
 | 
			
		||||
By convention, index getters are not supposed to mutate the [custom type],
 | 
			
		||||
although there is nothing that prevents this mutation.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: `EvalAltResult::ErrorIndexNotFound`"
 | 
			
		||||
 | 
			
		||||
For [fallible][fallible function] indexers, it is customary to return
 | 
			
		||||
`EvalAltResult::ErrorIndexNotFound` when called with an invalid index value.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Cannot Override Arrays, BLOB's, Object Maps, Strings and Integers
 | 
			
		||||
-----------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
```admonish failure.side "Plugins"
 | 
			
		||||
 | 
			
		||||
They can be defined in a [plugin module], but will be ignored.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For efficiency reasons, indexers **cannot** be used to overload (i.e. override)
 | 
			
		||||
built-in indexing operations for [arrays], [object maps], [strings] and integers
 | 
			
		||||
(acting as [bit-field] operation).
 | 
			
		||||
 | 
			
		||||
The following types have built-in indexer implementations that are fast and efficient.
 | 
			
		||||
 | 
			
		||||
<section></section>
 | 
			
		||||
 | 
			
		||||
| Type                                      |                Index type                 | Return type | Description                                                                  |
 | 
			
		||||
| ----------------------------------------- | :---------------------------------------: | :---------: | ---------------------------------------------------------------------------- |
 | 
			
		||||
| [`Array`]                                 |                   `INT`                   | [`Dynamic`] | access a particular element inside the [array]                               |
 | 
			
		||||
| [`Blob`]                                  |                   `INT`                   |    `INT`    | access a particular byte value inside the [BLOB]                             |
 | 
			
		||||
| [`Map`]                                   | [`ImmutableString`],<br/>`String`, `&str` | [`Dynamic`] | access a particular property inside the [object map]                         |
 | 
			
		||||
| [`ImmutableString`],<br/>`String`, `&str` |                   `INT`                   | [character] | access a particular [character] inside the [string]                          |
 | 
			
		||||
| `INT`                                     |                   `INT`                   |   boolean   | access a particular bit inside the integer number as a [bit-field]           |
 | 
			
		||||
| `INT`                                     |                  [range]                  |    `INT`    | access a particular range of bits inside the integer number as a [bit-field] |
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Do not overload indexers for built-in standard types"
 | 
			
		||||
 | 
			
		||||
In general, it is a bad idea to overload indexers for any of the [standard types] supported
 | 
			
		||||
internally by Rhai, since built-in indexers may be added in future versions.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Examples
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct TestStruct {
 | 
			
		||||
    fields: Vec<i64>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TestStruct {
 | 
			
		||||
    // Remember &mut must be used even for getters
 | 
			
		||||
    fn get_field(&mut self, index: String) -> i64 {
 | 
			
		||||
        self.fields[index.len()]
 | 
			
		||||
    }
 | 
			
		||||
    fn set_field(&mut self, index: String, value: i64) {
 | 
			
		||||
        self.fields[index.len()] = value
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self { fields: vec![1, 2, 3, 4, 5] }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_type::<TestStruct>()
 | 
			
		||||
      .register_fn("new_ts", TestStruct::new)
 | 
			
		||||
      // Short-hand: .register_indexer_get_set(TestStruct::get_field, TestStruct::set_field);
 | 
			
		||||
      .register_indexer_get(TestStruct::get_field)
 | 
			
		||||
      .register_indexer_set(TestStruct::set_field);
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>(
 | 
			
		||||
r#"
 | 
			
		||||
    let a = new_ts();
 | 
			
		||||
    a["xyz"] = 42;                  // these indexers use strings
 | 
			
		||||
    a["xyz"]                        // as the index type
 | 
			
		||||
"#)?;
 | 
			
		||||
 | 
			
		||||
println!("Answer: {result}");       // prints 42
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Convention for Negative Index
 | 
			
		||||
-----------------------------
 | 
			
		||||
 | 
			
		||||
If the indexer takes a signed integer as an index (e.g. the standard `INT` type), care should be
 | 
			
		||||
taken to handle _negative_ values passed as the index.
 | 
			
		||||
 | 
			
		||||
It is a standard API _convention_ for Rhai to assume that an index position counts _backwards_ from
 | 
			
		||||
the _end_ if it is negative.
 | 
			
		||||
 | 
			
		||||
`-1` as an index usually refers to the _last_ item, `-2` the second to last item, and so on.
 | 
			
		||||
 | 
			
		||||
Therefore, negative index values go from `-1` (last item) to `-length` (first item).
 | 
			
		||||
 | 
			
		||||
A typical implementation for negative index values is:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The following assumes:
 | 
			
		||||
//   'index' is 'INT', 'items: usize' is the number of elements
 | 
			
		||||
let actual_index = if index < 0 {
 | 
			
		||||
    index.checked_abs().map_or(0, |n| items - (n as usize).min(items))
 | 
			
		||||
} else {
 | 
			
		||||
    index as usize
 | 
			
		||||
};
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The _end_ of a data type can be interpreted creatively.  For example, in an integer used as a
 | 
			
		||||
[bit-field], the _start_ is the _least-significant-bit_ (LSB) while the `end` is the
 | 
			
		||||
_most-significant-bit_ (MSB).
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Convention for Range Index
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
```admonish tip.side.wide "Tip: Negative values"
 | 
			
		||||
 | 
			
		||||
By convention, negative values are _not_ interpreted specially in indexers for [ranges].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
It is very common for [ranges] to be used as indexer parameters via the types
 | 
			
		||||
`std::ops::Range<INT>` (exclusive) and `std::ops::RangeInclusive<INT>` (inclusive).
 | 
			
		||||
 | 
			
		||||
One complication is that two versions of the same indexer must be defined to support _exclusive_
 | 
			
		||||
and _inclusive_ [ranges] respectively.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use std::ops::{Range, RangeInclusive};
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine
 | 
			
		||||
    /// Version of indexer that accepts an exclusive range
 | 
			
		||||
    .register_indexer_get_set(
 | 
			
		||||
        |obj: &mut TestStruct, range: Range<i64>| -> bool { ... },
 | 
			
		||||
        |obj: &mut TestStruct, range: Range<i64>, value: bool| { ... },
 | 
			
		||||
    )
 | 
			
		||||
    /// Version of indexer that accepts an inclusive range
 | 
			
		||||
    .register_indexer_get_set(
 | 
			
		||||
        |obj: &mut TestStruct, range: RangeInclusive<i64>| -> bool { ... },
 | 
			
		||||
        |obj: &mut TestStruct, range: RangeInclusive<i64>, value: bool| { ... },
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
engine.run(
 | 
			
		||||
"
 | 
			
		||||
    let obj = new_ts();
 | 
			
		||||
 | 
			
		||||
    let x = obj[0..12];             // use exclusive range
 | 
			
		||||
 | 
			
		||||
    obj[0..=11] = !x;               // use inclusive range
 | 
			
		||||
")?;
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										180
									
								
								_archive/rhai_engine/rhaibook/rust/methods-fn-call.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										180
									
								
								_archive/rhai_engine/rhaibook/rust/methods-fn-call.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,180 @@
 | 
			
		||||
Call Method as Function
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Method-Call Style vs. Function-Call Style
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
### Method-call syntax
 | 
			
		||||
 | 
			
		||||
> _object_ `.` _function_ `(` _parameter_`,` ... `,` _parameter_`)`
 | 
			
		||||
 | 
			
		||||
~~~admonish warning.small "_Method-call_ style not supported under [`no_object`]"
 | 
			
		||||
```rust
 | 
			
		||||
// Below is a syntax error under 'no_object'.
 | 
			
		||||
engine.run("let x = [42]; x.clear();")?;
 | 
			
		||||
                        // ^ cannot call method-style
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
### Function-call syntax
 | 
			
		||||
 | 
			
		||||
> _function_ `(` _object_`,` _parameter_`,` ... `,` _parameter_`)`
 | 
			
		||||
 | 
			
		||||
### Equivalence
 | 
			
		||||
 | 
			
		||||
```admonish note.side
 | 
			
		||||
 | 
			
		||||
This design is similar to Rust.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Internally, methods on a [custom type] is _the same_ as a function taking a `&mut` first argument of
 | 
			
		||||
the object's type.
 | 
			
		||||
 | 
			
		||||
Therefore, methods and functions can be called interchangeably.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
impl TestStruct {
 | 
			
		||||
    fn foo(&mut self) -> i64 {
 | 
			
		||||
        self.field
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
engine.register_fn("foo", TestStruct::foo);
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>(
 | 
			
		||||
"
 | 
			
		||||
    let x = new_ts();
 | 
			
		||||
    foo(x);                         // normal call to 'foo'
 | 
			
		||||
    x.foo()                         // 'foo' can also be called like a method on 'x'
 | 
			
		||||
")?;
 | 
			
		||||
 | 
			
		||||
println!("result: {result}");       // prints 1
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
First `&mut` Parameter
 | 
			
		||||
----------------------
 | 
			
		||||
 | 
			
		||||
The opposite direction also works — methods in a Rust [custom type] registered with the
 | 
			
		||||
[`Engine`] can be called just like a regular function.  In fact, like Rust, 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 first `&mut` argument.
 | 
			
		||||
 | 
			
		||||
Sometimes, however, there are more subtle differences. Methods called in normal function-call style
 | 
			
		||||
may end up not muting the object afterall — see the example below.
 | 
			
		||||
 | 
			
		||||
Custom types, [properties][getters/setters], [indexers] and methods are disabled under the
 | 
			
		||||
[`no_object`] feature.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let a = new_ts();   // constructor function
 | 
			
		||||
a.field = 500;      // property setter
 | 
			
		||||
a.update();         // method call, 'a' can be modified
 | 
			
		||||
 | 
			
		||||
update(a);          // <- this de-sugars to 'a.update()'
 | 
			
		||||
                    //    'a' can be modified and is not a copy
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
                    //    except waste time cloning 'a'
 | 
			
		||||
 | 
			
		||||
array[0].update();  // <- call in method-call style will update 'a'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "No support for references"
 | 
			
		||||
 | 
			
		||||
Rhai does NOT support normal references (i.e. `&T`) as parameters.
 | 
			
		||||
All references must be mutable (i.e. `&mut T`).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Number of Parameters in Methods
 | 
			
		||||
-------------------------------
 | 
			
		||||
 | 
			
		||||
Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than
 | 
			
		||||
an equivalent method coded in script, where the object is accessed via the `this` pointer instead.
 | 
			
		||||
 | 
			
		||||
The following table illustrates the differences:
 | 
			
		||||
 | 
			
		||||
| Function type | No. of parameters |     Object reference     |      Function signature       |
 | 
			
		||||
| :-----------: | :---------------: | :----------------------: | :---------------------------: |
 | 
			
		||||
|  Native Rust  |      _N_ + 1      | first `&mut T` parameter | `Fn(obj: &mut T, x: U, y: V)` |
 | 
			
		||||
|  Rhai script  |        _N_        |          `this`          |       `Fn(x: U, y: V)`        |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`&mut` is Efficient, Except for `&mut ImmutableString`
 | 
			
		||||
------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
 | 
			
		||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
 | 
			
		||||
 | 
			
		||||
Even when a function is never intended to be a method – for example an operator,
 | 
			
		||||
it is still sometimes beneficial to make it method-like (i.e. with a first `&mut` parameter)
 | 
			
		||||
if the first parameter is not modified.
 | 
			
		||||
 | 
			
		||||
For types that are expensive to clone (remember, all function calls are passed cloned
 | 
			
		||||
copies of argument values), this may result in a significant performance boost.
 | 
			
		||||
 | 
			
		||||
For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`,
 | 
			
		||||
this is not necessary.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// This is a type that is very expensive to clone.
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct VeryComplexType { ... }
 | 
			
		||||
 | 
			
		||||
// Calculate some value by adding 'VeryComplexType' with an integer number.
 | 
			
		||||
fn do_add(obj: &VeryComplexType, offset: i64) -> i64 {
 | 
			
		||||
    ...
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
engine.register_type::<VeryComplexType>()
 | 
			
		||||
      .register_fn("+", add_pure /* or  add_method*/);
 | 
			
		||||
 | 
			
		||||
// Very expensive to call, as the 'VeryComplexType' is cloned before each call.
 | 
			
		||||
fn add_pure(obj: VeryComplexType, offset: i64) -> i64 {
 | 
			
		||||
    do_add(obj, offset)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Efficient to call, as only a reference to the 'VeryComplexType' is passed.
 | 
			
		||||
fn add_method(obj: &mut VeryComplexType, offset: i64) -> i64 {
 | 
			
		||||
    do_add(obj, offset)
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Data Race Considerations
 | 
			
		||||
------------------------
 | 
			
		||||
 | 
			
		||||
```admonish note.side "Data races"
 | 
			
		||||
 | 
			
		||||
Data races are not possible in Rhai under the [`no_closure`] feature because no sharing ever occurs.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Because methods always take a mutable reference as the first argument, even it the value is never changed,
 | 
			
		||||
care must be taken when using _shared_ values with methods.
 | 
			
		||||
 | 
			
		||||
Usually data races are not possible in Rhai because, for each function call, there is ever only one
 | 
			
		||||
value that is mutable – the first argument of a method.  All other arguments are cloned.
 | 
			
		||||
 | 
			
		||||
It is possible, however, to create a data race with a _shared_ value, when the same value is
 | 
			
		||||
_captured_ in a [closure] and then used again as the _object_ of calling that [closure]!
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let x = 20;
 | 
			
		||||
 | 
			
		||||
x.is_shared() == false;             // 'x' is not shared, so no data race is possible
 | 
			
		||||
 | 
			
		||||
let f = |a| this += x + a;          // 'x' is captured in this closure
 | 
			
		||||
 | 
			
		||||
x.is_shared() == true;              // now 'x' is shared
 | 
			
		||||
 | 
			
		||||
x.call(f, 2);                       // <- error: data race detected on 'x'
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										58
									
								
								_archive/rhai_engine/rhaibook/rust/methods.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								_archive/rhai_engine/rhaibook/rust/methods.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,58 @@
 | 
			
		||||
Methods
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Methods of [custom types] are registered via `Engine::register_fn`.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct TestStruct {
 | 
			
		||||
    field: i64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TestStruct {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self { field: 1 }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn update(&mut self, x: i64) {      // methods take &mut as first parameter
 | 
			
		||||
        self.field += x;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Most Engine APIs can be chained up.
 | 
			
		||||
engine.register_type_with_name::<TestStruct>("TestStruct")
 | 
			
		||||
      .register_fn("new_ts", TestStruct::new)
 | 
			
		||||
      .register_fn("update", TestStruct::update);
 | 
			
		||||
 | 
			
		||||
// Cast result back to custom type.
 | 
			
		||||
let result = engine.eval::<TestStruct>(
 | 
			
		||||
"
 | 
			
		||||
    let x = new_ts();                   // calls 'TestStruct::new'
 | 
			
		||||
    x.update(41);                       // calls 'TestStruct::update'
 | 
			
		||||
    x                                   // 'x' holds a 'TestStruct'
 | 
			
		||||
")?;
 | 
			
		||||
 | 
			
		||||
println!("result: {}", result.field);   // prints 42
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
First Parameter Must be `&mut`
 | 
			
		||||
------------------------------
 | 
			
		||||
 | 
			
		||||
_Methods_ of [custom types] take a `&mut` first parameter to that type, so that invoking methods can
 | 
			
		||||
always update it.
 | 
			
		||||
 | 
			
		||||
All other parameters in Rhai are passed by value (i.e. clones).
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "No support for references"
 | 
			
		||||
 | 
			
		||||
Rhai does NOT support normal references (i.e. `&T`) as parameters.
 | 
			
		||||
All references must be mutable (i.e. `&mut T`).
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										88
									
								
								_archive/rhai_engine/rhaibook/rust/modules/ast.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								_archive/rhai_engine/rhaibook/rust/modules/ast.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
Create a Module from an AST
 | 
			
		||||
===========================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`Module::eval_ast_as_new`
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
```admonish info.side.wide "Encapsulated environment"
 | 
			
		||||
 | 
			
		||||
`Module::eval_ast_as_new` encapsulates the entire [`AST`] into each function call, merging the
 | 
			
		||||
[module namespace][function namespace] with the [global namespace][function namespace].
 | 
			
		||||
 | 
			
		||||
Therefore, [functions] defined within the same [module] script can cross-call each other.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish info.side.wide "See also"
 | 
			
		||||
 | 
			
		||||
See [_Export Variables, Functions and Sub-Modules from Script_][`export`] for details on how to prepare
 | 
			
		||||
a Rhai script for this purpose as well as to control which [functions]/[variables] to export.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
A [module] can be created from a single script (or pre-compiled [`AST`]) containing global
 | 
			
		||||
[variables], [functions] and [sub-modules][module] via `Module::eval_ast_as_new`.
 | 
			
		||||
 | 
			
		||||
When given an [`AST`], it is first evaluated (usually to [import][`import`] [modules] and set up global
 | 
			
		||||
[constants] used by [functions]), then the following items are exposed as members of the new [module]:
 | 
			
		||||
 | 
			
		||||
* global [variables] and [constants] – all [variables] and [constants] exported via the
 | 
			
		||||
  [`export`] statement (those not exported remain hidden),
 | 
			
		||||
 | 
			
		||||
* [functions] not specifically marked [`private`],
 | 
			
		||||
 | 
			
		||||
* imported [modules] that remain in the [`Scope`] at the end of a script run become sub-modules.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Examples
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
Don't forget the [`export`] statement, otherwise there will be no [variables] exposed by the
 | 
			
		||||
[module] other than non-[`private`] [functions] (unless that's intentional).
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Module};
 | 
			
		||||
 | 
			
		||||
let engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Compile a script into an 'AST'
 | 
			
		||||
let ast = engine.compile(
 | 
			
		||||
r#"
 | 
			
		||||
    // Functions become module functions
 | 
			
		||||
    fn calc(x) {
 | 
			
		||||
        x + add_len(x, 1)       // functions within the same module
 | 
			
		||||
                                // can always cross-call each other!
 | 
			
		||||
    }
 | 
			
		||||
    fn add_len(x, y) {
 | 
			
		||||
        x + y.len
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Imported modules become sub-modules
 | 
			
		||||
    import "another module" as extra;
 | 
			
		||||
 | 
			
		||||
    // Variables defined at global level can become module variables
 | 
			
		||||
    const x = 123;
 | 
			
		||||
    let foo = 41;
 | 
			
		||||
    let hello;
 | 
			
		||||
 | 
			
		||||
    // Variable values become constant module variable values
 | 
			
		||||
    foo = calc(foo);
 | 
			
		||||
    hello = `hello, ${foo} worlds!`;
 | 
			
		||||
 | 
			
		||||
    // Finally, export the variables and modules
 | 
			
		||||
    export x as abc;            // aliased variable name
 | 
			
		||||
    export foo;
 | 
			
		||||
    export hello;
 | 
			
		||||
"#)?;
 | 
			
		||||
 | 
			
		||||
// Convert the 'AST' into a module, using the 'Engine' to evaluate it first
 | 
			
		||||
// A copy of the entire 'AST' is encapsulated into each function,
 | 
			
		||||
// allowing functions in the module script to cross-call each other.
 | 
			
		||||
let module = Module::eval_ast_as_new(Scope::new(), &ast, &engine)?;
 | 
			
		||||
 | 
			
		||||
// 'module' now contains:
 | 
			
		||||
//   - sub-module: 'extra'
 | 
			
		||||
//   - functions: 'calc', 'add_len'
 | 
			
		||||
//   - constants: 'abc' (renamed from 'x'), 'foo', 'hello'
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										24
									
								
								_archive/rhai_engine/rhaibook/rust/modules/create.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								_archive/rhai_engine/rhaibook/rust/modules/create.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
			
		||||
Create a Module in Rust
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The Easy Way – Plugin
 | 
			
		||||
---------------------------
 | 
			
		||||
 | 
			
		||||
By far the simplest way to create a [module] is via a [plugin module]
 | 
			
		||||
which converts a normal Rust module into a Rhai [module] via procedural macros.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The Hard Way – `Module` API
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
Manually creating a [module] is possible via the [`Module`] public API, which is volatile and may
 | 
			
		||||
change from time to time.
 | 
			
		||||
 | 
			
		||||
~~~admonish info.small "`Module` public API"
 | 
			
		||||
 | 
			
		||||
For the complete [`Module`] public API, refer to the
 | 
			
		||||
[documentation](https://docs.rs/rhai/{{version}}/rhai/struct.Module.html) online.
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										30
									
								
								_archive/rhai_engine/rhaibook/rust/modules/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								_archive/rhai_engine/rhaibook/rust/modules/index.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,30 @@
 | 
			
		||||
Modules
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
Rhai allows organizing functionalities ([functions], both Rust-based and scripted, and
 | 
			
		||||
[variables]) into independent _modules_.
 | 
			
		||||
 | 
			
		||||
A module has the type `rhai::Module` and holds a collection of [functions], [variables], [type
 | 
			
		||||
iterators] and sub-modules.
 | 
			
		||||
 | 
			
		||||
It may contain entirely Rust functions, or it may encapsulate a Rhai script together with
 | 
			
		||||
all the [functions] and [variables] defined by that script.
 | 
			
		||||
 | 
			
		||||
Other scripts then load this module and use the [functions] and [variables] [exported][`export`].
 | 
			
		||||
 | 
			
		||||
Alternatively, modules can be registered directly into an [`Engine`] and made available to scripts,
 | 
			
		||||
either globally or under individual static module [_namespaces_][function namespaces].
 | 
			
		||||
 | 
			
		||||
Modules can be disabled via the [`no_module`] feature.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Usage Patterns
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
| Usage          |                API                |          Lookup          | Sub-modules? | Variables? |
 | 
			
		||||
| -------------- | :-------------------------------: | :----------------------: | :----------: | :--------: |
 | 
			
		||||
| Global module  | `Engine:: register_global_module` |       simple name        |   ignored    |    yes     |
 | 
			
		||||
| Static module  | `Engine:: register_static_module` | namespace-qualified name |     yes      |    yes     |
 | 
			
		||||
| Dynamic module |       [`import`] statement        | namespace-qualified name |     yes      |    yes     |
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
Built-in Module Resolvers
 | 
			
		||||
=========================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
There are a number of standard [module resolvers] built into Rhai, the default being the
 | 
			
		||||
[`FileModuleResolver`](file.md) which simply loads a script file based on the path (with `.rhai`
 | 
			
		||||
extension attached) and execute it to form a [module].
 | 
			
		||||
 | 
			
		||||
Built-in [module resolvers] are grouped under the `rhai::module_resolvers` module.
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
`ModuleResolversCollection`
 | 
			
		||||
===========================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
A collection of [module resolvers].
 | 
			
		||||
 | 
			
		||||
[Modules] are resolved from each resolver in sequential order.
 | 
			
		||||
 | 
			
		||||
This is useful when multiple types of [modules] are needed simultaneously.
 | 
			
		||||
@@ -0,0 +1,95 @@
 | 
			
		||||
Implement a Custom Module Resolver
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
For many applications in which Rhai is embedded, it is necessary to customize the way that [modules]
 | 
			
		||||
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 [`ModuleResolver`][traits] trait, which contains only one
 | 
			
		||||
required 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).
 | 
			
		||||
 | 
			
		||||
```admonish success
 | 
			
		||||
Upon success, it should return a shared [module] wrapped by `Rc` (or `Arc` under [`sync`]).
 | 
			
		||||
  
 | 
			
		||||
The module resolver should call `Module::build_index` on the target [module] before returning it.
 | 
			
		||||
* This method flattens the entire module tree and _indexes_ it for fast function name resolution.
 | 
			
		||||
* If the module is already indexed, calling this method has no effect.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish failure
 | 
			
		||||
 | 
			
		||||
* If the path does not resolve to a valid module, return `EvalAltResult::ErrorModuleNotFound`.
 | 
			
		||||
 | 
			
		||||
* If the module failed to load, return `EvalAltResult::ErrorInModule`.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Example of a Custom Module Resolver
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{ModuleResolver, Module, Engine, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
// Define a custom module resolver.
 | 
			
		||||
struct MyModuleResolver {}
 | 
			
		||||
 | 
			
		||||
// Implement the 'ModuleResolver' trait.
 | 
			
		||||
impl ModuleResolver for MyModuleResolver {
 | 
			
		||||
    // Only required function.
 | 
			
		||||
    fn resolve(
 | 
			
		||||
        &self,
 | 
			
		||||
        engine: &Engine,                        // reference to the current 'Engine'
 | 
			
		||||
        source_path: Option<&str>,              // path of the parent module
 | 
			
		||||
        path: &str,                             // the module path
 | 
			
		||||
        pos: Position,                          // position of the 'import' statement
 | 
			
		||||
    ) -> Result<Rc<Module>, Box<EvalAltResult>> {
 | 
			
		||||
        // Check module path.
 | 
			
		||||
        if is_valid_module_path(path) {
 | 
			
		||||
            // Load the custom module
 | 
			
		||||
            match load_secret_module(path) {
 | 
			
		||||
                Ok(my_module) => {
 | 
			
		||||
                    my_module.build_index();    // index it
 | 
			
		||||
                    Rc::new(my_module)          // make it shared
 | 
			
		||||
                },
 | 
			
		||||
                // Return 'EvalAltResult::ErrorInModule' upon loading error
 | 
			
		||||
                Err(err) => Err(EvalAltResult::ErrorInModule(path.into(), Box::new(err), pos).into())
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            // Return 'EvalAltResult::ErrorModuleNotFound' if the path is invalid
 | 
			
		||||
            Err(EvalAltResult::ErrorModuleNotFound(path.into(), pos).into())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Set the custom module resolver into the 'Engine'.
 | 
			
		||||
engine.set_module_resolver(MyModuleResolver {});
 | 
			
		||||
 | 
			
		||||
engine.run(
 | 
			
		||||
r#"
 | 
			
		||||
    import "hello" as foo;  // this 'import' statement will call
 | 
			
		||||
                            // 'MyModuleResolver::resolve' with "hello" as 'path'
 | 
			
		||||
    foo:bar();
 | 
			
		||||
"#)?;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Advanced – `ModuleResolver::resolve_ast`
 | 
			
		||||
----------------------------------------------
 | 
			
		||||
 | 
			
		||||
There is another function in the [`ModuleResolver`][traits] trait, `resolve_ast`, which is a
 | 
			
		||||
low-level API intended for advanced usage scenarios.
 | 
			
		||||
 | 
			
		||||
`ModuleResolver::resolve_ast` has a default implementation that simply returns `None`,
 | 
			
		||||
which indicates that this API is not supported by the [module resolver].
 | 
			
		||||
 | 
			
		||||
Any [module resolver] that serves [modules] based on Rhai scripts should implement
 | 
			
		||||
`ModuleResolver::resolve_ast`. When called, the compiled [`AST`] of the script should be returned.
 | 
			
		||||
 | 
			
		||||
`ModuleResolver::resolve_ast` should not return an error if `ModuleResolver::resolve` will not.
 | 
			
		||||
On the other hand, the same error should be returned if `ModuleResolver::resolve` will return one.
 | 
			
		||||
@@ -0,0 +1,11 @@
 | 
			
		||||
`DummyModuleResolver`
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish abstract.small "Default"
 | 
			
		||||
 | 
			
		||||
`DummyModuleResolver` is the default for [`no_std`] or [`Engine::new_raw`][raw `Engine`].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
This [module resolver] acts as a _dummy_ and fails all module resolution calls.
 | 
			
		||||
@@ -0,0 +1,64 @@
 | 
			
		||||
`DylibModuleResolver`
 | 
			
		||||
=====================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish warning.small "Requires external crate `rhai-dylib`"
 | 
			
		||||
 | 
			
		||||
`DylibModuleResolver` resides in the [`rhai-dylib`] crate which must be specified
 | 
			
		||||
as a dependency:
 | 
			
		||||
 | 
			
		||||
```toml
 | 
			
		||||
[dependencies]
 | 
			
		||||
rhai-dylib = { version = "0.1" }
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "Linux or Windows only"
 | 
			
		||||
 | 
			
		||||
[`rhai-dylib`] currently supports only Linux and Windows.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Parallel to how the [`FileModuleResolver`](file.md) works, `DylibModuleResolver` loads external
 | 
			
		||||
native Rust [modules] from compiled _dynamic shared libraries_ (e.g. `.so` in Linux and `.dll` in
 | 
			
		||||
Windows).
 | 
			
		||||
 | 
			
		||||
Therefore, [`FileModuleResolver`](file.md`) loads Rhai script files while `DylibModuleResolver`
 | 
			
		||||
loads native Rust shared libraries.  It is very common to have the two work together.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Module};
 | 
			
		||||
use rhai::module_resolvers::{FileModuleResolver, ModuleResolversCollection};
 | 
			
		||||
use rhai_dylib::module_resolvers::DylibModuleResolver;
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Use a module resolvers collection
 | 
			
		||||
let mut resolvers = ModuleResolversCollection::new();
 | 
			
		||||
 | 
			
		||||
// First search for script files in the file system
 | 
			
		||||
resolvers += FileModuleResolver::new();
 | 
			
		||||
 | 
			
		||||
// Then search for shared-library plugins in the file system
 | 
			
		||||
resolvers += DylibModuleResolver::new();
 | 
			
		||||
 | 
			
		||||
// Set the module resolver into the engine
 | 
			
		||||
engine.set_module_resolver(resolvers);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
┌─────────────┐
 | 
			
		||||
│ Rhai Script │
 | 
			
		||||
└─────────────┘
 | 
			
		||||
 | 
			
		||||
// If there is 'path/to/my_module.rhai', load it.
 | 
			
		||||
// Otherwise, check for 'path/to/my_module.so' on Linux
 | 
			
		||||
// ('path/to/my_module.dll' on Windows).
 | 
			
		||||
import "path/to/my_module" as m;
 | 
			
		||||
 | 
			
		||||
m::greet();
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										183
									
								
								_archive/rhai_engine/rhaibook/rust/modules/resolvers/file.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								_archive/rhai_engine/rhaibook/rust/modules/resolvers/file.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
			
		||||
`FileModuleResolver`
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish abstract.small "Default"
 | 
			
		||||
 | 
			
		||||
`FileModuleResolver` is the default for [`Engine::new`][`Engine`].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The _default_ [module] resolution service, not available for [`no_std`] or [WASM] builds.
 | 
			
		||||
Loads a script file (based off the current directory or a specified one) with `.rhai` extension.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Function Namespace
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
All functions in the [_global_ namespace][function namespace], plus all those defined in the same
 | 
			
		||||
[module], are _merged_ into a _unified_ [namespace][function namespace].
 | 
			
		||||
 | 
			
		||||
All [modules] imported at _global_ level via [`import`] statements become sub-[modules],
 | 
			
		||||
which are also available to [functions] defined within the same script file.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Base Directory
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
```admonish tip.side.wide "Tip: Default"
 | 
			
		||||
 | 
			
		||||
If the base directory is not set, then relative paths are based off the directory of the loading script.
 | 
			
		||||
 | 
			
		||||
This allows scripts to simply cross-load each other.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
_Relative_ paths are resolved relative to a _root_ directory, which is usually the base directory.
 | 
			
		||||
 | 
			
		||||
The base directory can be set via `FileModuleResolver::new_with_path` or
 | 
			
		||||
`FileModuleResolver::set_base_path`.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Custom [`Scope`]
 | 
			
		||||
----------------
 | 
			
		||||
 | 
			
		||||
```admonish tip.side.wide "Tip"
 | 
			
		||||
 | 
			
		||||
This [`Scope`] can conveniently hold global [constants] etc.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The `set_scope` method adds an optional [`Scope`] which will be used to [optimize][script optimization] [module] scripts.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Caching
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
```admonish tip.side.wide "Tip: Enable/disable caching"
 | 
			
		||||
 | 
			
		||||
Use `enable_cache` to enable/disable the cache.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
By default, [modules] are also _cached_ so a script file is only evaluated _once_, even when
 | 
			
		||||
repeatedly imported.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Unix Shebangs
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
On Unix-like systems, the _shebang_ (`#!`) is used at the very beginning of a script file to mark a
 | 
			
		||||
script with an interpreter (for Rhai this would be [`rhai-run`]({{rootUrl}}/start/bin.md)).
 | 
			
		||||
 | 
			
		||||
If a script file starts with `#!`, the entire first line is skipped.
 | 
			
		||||
Because of this, Rhai scripts with shebangs at the beginning need no special processing.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
#!/home/to/me/bin/rhai-run
 | 
			
		||||
 | 
			
		||||
// This is a Rhai script
 | 
			
		||||
 | 
			
		||||
let answer = 42;
 | 
			
		||||
print(`The answer is: ${answer}`);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
┌────────────────┐
 | 
			
		||||
│ my_module.rhai │
 | 
			
		||||
└────────────────┘
 | 
			
		||||
 | 
			
		||||
// This function overrides any in the main script.
 | 
			
		||||
private fn inner_message() { "hello! from module!" }
 | 
			
		||||
 | 
			
		||||
fn greet() {
 | 
			
		||||
    print(inner_message());     // call function in module script
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn greet_main() {
 | 
			
		||||
    print(main_message());      // call function not in module script
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
┌───────────┐
 | 
			
		||||
│ main.rhai │
 | 
			
		||||
└───────────┘
 | 
			
		||||
 | 
			
		||||
// This function is overridden by the module script.
 | 
			
		||||
fn inner_message() { "hi! from main!" }
 | 
			
		||||
 | 
			
		||||
// This function is found by the module script.
 | 
			
		||||
fn main_message() { "main here!" }
 | 
			
		||||
 | 
			
		||||
import "my_module" as m;
 | 
			
		||||
 | 
			
		||||
m::greet();                     // prints "hello! from module!"
 | 
			
		||||
 | 
			
		||||
m::greet_main();                // prints "main here!"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Simulate Virtual Functions
 | 
			
		||||
--------------------------
 | 
			
		||||
 | 
			
		||||
When calling a namespace-qualified [function] defined within a [module], other [functions] defined
 | 
			
		||||
within the same module override any similar-named [functions] (with the same number of parameters)
 | 
			
		||||
defined in the [global namespace][function namespace].
 | 
			
		||||
 | 
			
		||||
This is to ensure that a [module] acts as a self-contained unit and [functions] defined in the
 | 
			
		||||
calling script do not override [module] code.
 | 
			
		||||
 | 
			
		||||
In some situations, however, it is actually beneficial to do it in reverse: have [module] [functions] call
 | 
			
		||||
[functions] defined in the calling script (i.e. in the [global namespace][function namespace]) if
 | 
			
		||||
they exist, and only call those defined in the [module] if none are found.
 | 
			
		||||
 | 
			
		||||
One such situation is the need to provide a _default implementation_ to a simulated _virtual_ function:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
┌────────────────┐
 | 
			
		||||
│ my_module.rhai │
 | 
			
		||||
└────────────────┘
 | 
			
		||||
 | 
			
		||||
// Do not do this (it will override the main script):
 | 
			
		||||
// fn message() { "hello! from module!" }
 | 
			
		||||
 | 
			
		||||
// This function acts as the default implementation.
 | 
			
		||||
private fn default_message() { "hello! from module!" }
 | 
			
		||||
 | 
			
		||||
// This function depends on a 'virtual' function 'message'
 | 
			
		||||
// which is not defined in the module script.
 | 
			
		||||
fn greet() {
 | 
			
		||||
    if is_def_fn("message", 0) {    // 'is_def_fn' detects if 'message' is defined.
 | 
			
		||||
        print(message());
 | 
			
		||||
    } else {
 | 
			
		||||
        print(default_message());
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
┌───────────┐
 | 
			
		||||
│ main.rhai │
 | 
			
		||||
└───────────┘
 | 
			
		||||
 | 
			
		||||
// The main script defines 'message' which is needed by the module script.
 | 
			
		||||
fn message() { "hi! from main!" }
 | 
			
		||||
 | 
			
		||||
import "my_module" as m;
 | 
			
		||||
 | 
			
		||||
m::greet();                         // prints "hi! from main!"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
┌────────────┐
 | 
			
		||||
│ main2.rhai │
 | 
			
		||||
└────────────┘
 | 
			
		||||
 | 
			
		||||
// The main script does not define 'message' which is needed by the module script.
 | 
			
		||||
 | 
			
		||||
import "my_module" as m;
 | 
			
		||||
 | 
			
		||||
m::greet();                         // prints "hello! from module!"
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
Module Resolvers
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
~~~admonish info.side "`import`"
 | 
			
		||||
 | 
			
		||||
See the section on [_Importing Modules_][`import`] for more details.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
When encountering an [`import`] statement, Rhai attempts to _resolve_ the [module] based on the path string.
 | 
			
		||||
 | 
			
		||||
_Module Resolvers_ are service types that implement the [`ModuleResolver`][traits] trait.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Set into `Engine`
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
An [`Engine`]'s module resolver is set via a call to `Engine::set_module_resolver`:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::module_resolvers::{DummyModuleResolver, StaticModuleResolver};
 | 
			
		||||
 | 
			
		||||
// Create a module resolver
 | 
			
		||||
let resolver = StaticModuleResolver::new();
 | 
			
		||||
 | 
			
		||||
// Register functions into 'resolver'...
 | 
			
		||||
 | 
			
		||||
// Use the module resolver
 | 
			
		||||
engine.set_module_resolver(resolver);
 | 
			
		||||
 | 
			
		||||
// Effectively disable 'import' statements by setting module resolver to
 | 
			
		||||
// the 'DummyModuleResolver' which acts as... well... a dummy.
 | 
			
		||||
engine.set_module_resolver(DummyModuleResolver::new());
 | 
			
		||||
```
 | 
			
		||||
@@ -0,0 +1,26 @@
 | 
			
		||||
`StaticModuleResolver`
 | 
			
		||||
======================
 | 
			
		||||
 | 
			
		||||
{{#include ../../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish abstract.small "Useful for `no-std`"
 | 
			
		||||
 | 
			
		||||
`StaticModuleResolver` is often used with [`no_std`] in embedded environments
 | 
			
		||||
without a file system.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
Loads [modules] that are statically added.
 | 
			
		||||
 | 
			
		||||
Functions are searched in the [_global_ namespace][function namespace] by default.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Module, module_resolvers::StaticModuleResolver};
 | 
			
		||||
 | 
			
		||||
let module: Module = create_a_module();
 | 
			
		||||
 | 
			
		||||
let mut resolver = StaticModuleResolver::new();
 | 
			
		||||
resolver.insert("my_module", module);
 | 
			
		||||
 | 
			
		||||
engine.set_module_resolver(resolver);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										70
									
								
								_archive/rhai_engine/rhaibook/rust/modules/self-contained.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								_archive/rhai_engine/rhaibook/rust/modules/self-contained.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,70 @@
 | 
			
		||||
Compile to a Self-Contained `AST`
 | 
			
		||||
=================================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish tip.side "Tip"
 | 
			
		||||
 | 
			
		||||
It does not matter where the [`import`] statement occurs — e.g. deep within statements blocks
 | 
			
		||||
or within [function] bodies.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When a script [imports][`import`] external [modules] that may not be available later on, it is
 | 
			
		||||
possible to eagerly [_pre-resolve_][module resolver] these imports and embed them directly into a
 | 
			
		||||
self-contained [`AST`].
 | 
			
		||||
 | 
			
		||||
For instance, a system may periodically connect to a central source (e.g. a database) to load
 | 
			
		||||
scripts and compile them to [`AST`] form. Afterwards, in order to conserve bandwidth (or due to
 | 
			
		||||
other physical limitations), it is disconnected from the central source for self-contained
 | 
			
		||||
operation.
 | 
			
		||||
 | 
			
		||||
Compile a script into a _self-contained_ [`AST`] via `Engine::compile_into_self_contained`.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Compile script into self-contained AST using the current
 | 
			
		||||
// module resolver (default to `FileModuleResolver`) to pre-resolve
 | 
			
		||||
// 'import' statements.
 | 
			
		||||
let ast = engine.compile_into_self_contained(&mut scope, script)?;
 | 
			
		||||
 | 
			
		||||
// Make sure we can no longer resolve any module!
 | 
			
		||||
engine.set_module_resolver(DummyModuleResolver::new());
 | 
			
		||||
 | 
			
		||||
// The AST still evaluates fine, even with 'import' statements!
 | 
			
		||||
engine.run(&ast)?;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When such an [`AST`] is evaluated, [`import`] statements within are provided the _pre-resolved_
 | 
			
		||||
[modules] without going through the normal [module resolution][module resolver] process.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Only Static Paths
 | 
			
		||||
-----------------
 | 
			
		||||
 | 
			
		||||
`Engine::compile_into_self_contained` only pre-resolves [`import`] statements in the script
 | 
			
		||||
that are _static_, i.e. with a path that is a [string] literal.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The following import is pre-resolved.
 | 
			
		||||
import "hello" as h;
 | 
			
		||||
 | 
			
		||||
if some_event() {
 | 
			
		||||
    // The following import is pre-resolved.
 | 
			
		||||
    import "hello" as h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn foo() {
 | 
			
		||||
    // The following import is pre-resolved.
 | 
			
		||||
    import "hello" as h;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// The following import is also pre-resolved because the expression
 | 
			
		||||
// is usually optimized into a single string during compilation.
 | 
			
		||||
import "he" + "llo" as h;
 | 
			
		||||
 | 
			
		||||
let module_name = "hello";
 | 
			
		||||
 | 
			
		||||
// The following import is NOT pre-resolved.
 | 
			
		||||
import module_name as h;
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										183
									
								
								_archive/rhai_engine/rhaibook/rust/modules/use.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								_archive/rhai_engine/rhaibook/rust/modules/use.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,183 @@
 | 
			
		||||
Make a Module Available to Scripts
 | 
			
		||||
==================================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Use Case 1 – Make It Globally Available
 | 
			
		||||
---------------------------------------------
 | 
			
		||||
 | 
			
		||||
`Engine::register_global_module` registers a shared [module] into the
 | 
			
		||||
[_global_ namespace][function namespace].
 | 
			
		||||
 | 
			
		||||
This is by far the easiest way to expose a [module]'s functionalities to Rhai.
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: No qualifiers"
 | 
			
		||||
 | 
			
		||||
All [functions], [variables]/[constants] and [type iterators] can be accessed without
 | 
			
		||||
_namespace qualifiers_.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.small
 | 
			
		||||
 | 
			
		||||
[Sub-modules][module] are **ignored**.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Module, FuncRegistration};
 | 
			
		||||
 | 
			
		||||
let mut module = Module::new();             // new module
 | 
			
		||||
 | 
			
		||||
// Add new function.
 | 
			
		||||
FuncRegistration::new("inc")
 | 
			
		||||
    .with_params_info(&["x: i64", "i64"])
 | 
			
		||||
    .set_into_module(&mut module, |x: i64| x + 1);
 | 
			
		||||
 | 
			
		||||
// Use 'Module::set_var' to add variables.
 | 
			
		||||
module.set_var("MYSTIC_NUMBER", 41_i64);
 | 
			
		||||
 | 
			
		||||
// Register the module into the global namespace of the Engine.
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
engine.register_global_module(module.into());
 | 
			
		||||
 | 
			
		||||
// No need to import module...
 | 
			
		||||
engine.eval::<i64>("inc(MYSTIC_NUMBER)")? == 42;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Equivalent to `Engine::register_XXX`
 | 
			
		||||
 | 
			
		||||
```admonish question.side "Trivia"
 | 
			
		||||
 | 
			
		||||
`Engine::register_fn` etc. are actually implemented by adding functions to an
 | 
			
		||||
internal [module]!
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Registering a [module] via `Engine::register_global_module` is essentially the _same_
 | 
			
		||||
as calling `Engine::register_fn` (or any of the `Engine::register_XXX` API) individually
 | 
			
		||||
on each top-level function within that [module].
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The above is essentially the same as:
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
engine.register_fn("inc", |x: i64| x + 1);
 | 
			
		||||
 | 
			
		||||
engine.eval::<i64>("inc(41)")? == 42;       // no need to import module
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Use Case 2 – Make It a Static Namespace
 | 
			
		||||
---------------------------------------------
 | 
			
		||||
 | 
			
		||||
`Engine::register_static_module` registers a [module] and under a specific
 | 
			
		||||
[module namespace][function namespace].
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Module, FuncRegistration};
 | 
			
		||||
 | 
			
		||||
let mut module = Module::new();             // new module
 | 
			
		||||
 | 
			
		||||
// Add new function.
 | 
			
		||||
FuncRegistration::new("inc")
 | 
			
		||||
    .with_params_info(&["x: i64", "i64"])
 | 
			
		||||
    .set_into_module(&mut module, |x: i64| x + 1);
 | 
			
		||||
 | 
			
		||||
// Use 'Module::set_var' to add variables.
 | 
			
		||||
module.set_var("MYSTIC_NUMBER", 41_i64);
 | 
			
		||||
 | 
			
		||||
// Register the module into the Engine as the static module namespace path
 | 
			
		||||
// 'services::calc'
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
engine.register_static_module("services::calc", module.into());
 | 
			
		||||
 | 
			
		||||
// Refer to the 'services::calc' module...
 | 
			
		||||
engine.eval::<i64>("services::calc::inc(services::calc::MYSTIC_NUMBER)")? == 42;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Expose functions to the global namespace
 | 
			
		||||
 | 
			
		||||
```admonish tip.side "Tip: Type iterators"
 | 
			
		||||
 | 
			
		||||
[Type iterators] are special — they are _always_ exposed to the
 | 
			
		||||
[_global_ namespace][function namespace].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The [`Module`] API can optionally expose functions to the [_global_ namespace][function namespace]
 | 
			
		||||
by setting the `namespace` parameter to `FnNamespace::Global`.
 | 
			
		||||
 | 
			
		||||
This way, [getters/setters] and [indexers] for [custom types] can work as expected.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Module, FuncRegistration, FnNamespace};
 | 
			
		||||
 | 
			
		||||
let mut module = Module::new();             // new module
 | 
			
		||||
 | 
			
		||||
// Add new function.
 | 
			
		||||
FuncRegistration::new("inc")
 | 
			
		||||
    .with_params_info(&["x: i64", "i64"])
 | 
			
		||||
    .with_namespace(FnNamespace::Global)    // <- global namespace
 | 
			
		||||
    .set_into_module(&mut module, |x: i64| x + 1);
 | 
			
		||||
 | 
			
		||||
// Use 'Module::set_var' to add variables.
 | 
			
		||||
module.set_var("MYSTIC_NUMBER", 41_i64);
 | 
			
		||||
 | 
			
		||||
// Register the module into the Engine as a static module namespace 'calc'
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
engine.register_static_module("calc", module.into());
 | 
			
		||||
 | 
			
		||||
// 'inc' works when qualified by the namespace
 | 
			
		||||
engine.eval::<i64>("calc::inc(calc::MYSTIC_NUMBER)")? == 42;
 | 
			
		||||
 | 
			
		||||
// 'inc' also works without a namespace qualifier
 | 
			
		||||
// because it is exposed to the global namespace
 | 
			
		||||
engine.eval::<i64>("let x = calc::MYSTIC_NUMBER; x.inc()")? == 42;
 | 
			
		||||
engine.eval::<i64>("let x = calc::MYSTIC_NUMBER; inc(x)")? == 42;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Use Case 3 – Make It Dynamically Loadable
 | 
			
		||||
-----------------------------------------------
 | 
			
		||||
 | 
			
		||||
In order to dynamically load a custom module, there must be a [module resolver] which serves
 | 
			
		||||
the module when loaded via `import` statements.
 | 
			
		||||
 | 
			
		||||
The easiest way is to use, for example, the [`StaticModuleResolver`][module resolver] to hold such
 | 
			
		||||
a custom module.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Scope, Module, FuncRegistration};
 | 
			
		||||
use rhai::module_resolvers::StaticModuleResolver;
 | 
			
		||||
 | 
			
		||||
let mut module = Module::new();             // new module
 | 
			
		||||
 | 
			
		||||
module.set_var("answer", 41_i64);           // variable 'answer' under module
 | 
			
		||||
 | 
			
		||||
FuncRegistration::new("inc")
 | 
			
		||||
    .with_params_info(&["x: i64"])
 | 
			
		||||
    .set_into_module(&mut module, |x: i64| x + 1);
 | 
			
		||||
 | 
			
		||||
// Create the module resolver
 | 
			
		||||
let mut resolver = StaticModuleResolver::new();
 | 
			
		||||
 | 
			
		||||
// Add the module into the module resolver under the name 'question'
 | 
			
		||||
// They module can then be accessed via: 'import "question" as q;'
 | 
			
		||||
resolver.insert("question", module);
 | 
			
		||||
 | 
			
		||||
// Set the module resolver into the 'Engine'
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
engine.set_module_resolver(resolver);
 | 
			
		||||
 | 
			
		||||
// Use namespace-qualified variables
 | 
			
		||||
engine.eval::<i64>(
 | 
			
		||||
r#"
 | 
			
		||||
    import "question" as q;
 | 
			
		||||
    q::answer + 1
 | 
			
		||||
"#)? == 42;
 | 
			
		||||
 | 
			
		||||
// Call namespace-qualified functions
 | 
			
		||||
engine.eval::<i64>(
 | 
			
		||||
r#"
 | 
			
		||||
    import "question" as q;
 | 
			
		||||
    q::inc(q::answer)
 | 
			
		||||
"#)? == 42;
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										91
									
								
								_archive/rhai_engine/rhaibook/rust/operators.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								_archive/rhai_engine/rhaibook/rust/operators.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,91 @@
 | 
			
		||||
Operator Overloading
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
In Rhai, a lot of functionalities are actually implemented as functions, including basic operations
 | 
			
		||||
such as arithmetic calculations.
 | 
			
		||||
 | 
			
		||||
For example, in the expression "`a + b`", the `+` [operator] actually calls a function named "`+`"!
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let x = a + b;
 | 
			
		||||
 | 
			
		||||
let x = +(a, b);        // <- the above is equivalent to this function call
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Similarly, comparison [operators] including `==`, `!=` etc. are all implemented as functions,
 | 
			
		||||
with the stark exception of `&&`, `||` and `??`.
 | 
			
		||||
 | 
			
		||||
~~~admonish warning.small "`&&`, `||` and `??` cannot be overloaded"
 | 
			
		||||
 | 
			
		||||
Because they [_short-circuit_]({{rootUrl}}/language/logic.md#boolean-operators), `&&`, `||` and `??` are
 | 
			
		||||
handled specially and _not_ via a function.
 | 
			
		||||
 | 
			
		||||
Overriding them has no effect at all.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Overload Operator via Rust Function
 | 
			
		||||
-----------------------------------
 | 
			
		||||
 | 
			
		||||
[Operator] functions cannot be defined in script because [operators] are usually not valid function names.
 | 
			
		||||
 | 
			
		||||
However, [operator] functions _can_ be registered via `Engine::register_fn`.
 | 
			
		||||
 | 
			
		||||
When a custom [operator] function is registered with the same name as an [operator],
 | 
			
		||||
it _overrides_ the built-in version.  However, make sure the [_Fast Operators Mode_][fast operators]
 | 
			
		||||
is disabled; otherwise this will not work.
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Must turn off _Fast Operators Mode_"
 | 
			
		||||
 | 
			
		||||
The [_Fast Operators Mode_][fast operators], which is enabled by default, causes the [`Engine`]
 | 
			
		||||
to _ignore_ all custom-registered operator functions for [built-in operators].  This is for
 | 
			
		||||
performance considerations.
 | 
			
		||||
 | 
			
		||||
Disable [_Fast Operators Mode_][fast operators] via [`Engine::set_fast_operators`][options]
 | 
			
		||||
in order for the overloaded operators to be used.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
fn strange_add(a: i64, b: i64) -> i64 {
 | 
			
		||||
    (a + b) * 42
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
engine.register_fn("+", strange_add);               // overload '+' operator for two integers!
 | 
			
		||||
 | 
			
		||||
engine.set_fast_operators(false);                   // <- IMPORTANT! must turn off Fast Operators Mode
 | 
			
		||||
 | 
			
		||||
let result: i64 = engine.eval("1 + 0");             // the overloading version is used
 | 
			
		||||
 | 
			
		||||
result == 42;
 | 
			
		||||
 | 
			
		||||
let result: f64 = engine.eval("1.0 + 0.0");         // '+' operator for two floats not overloaded
 | 
			
		||||
 | 
			
		||||
result == 1.0;
 | 
			
		||||
 | 
			
		||||
fn mixed_add(a: i64, b: bool) -> f64 { a + if b { 42 } else { 99 } }
 | 
			
		||||
 | 
			
		||||
engine.register_fn("+", mixed_add);                 // register '+' operator for an integer and a bool
 | 
			
		||||
 | 
			
		||||
let result: i64 = engine.eval("1 + true");          // <- normally an error...
 | 
			
		||||
 | 
			
		||||
result == 43;                                       //    ... but not now
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish danger.small "Considerations"
 | 
			
		||||
 | 
			
		||||
Use [operator] overloading for [custom types] only.
 | 
			
		||||
 | 
			
		||||
Be **very careful** when overriding built-in [operators] because users expect standard [operators] to
 | 
			
		||||
behave in a consistent and predictable manner, and will be annoyed if an expression involving `+`
 | 
			
		||||
turns into a subtraction, for example.  You may think it is amusing, but users who need to get
 | 
			
		||||
things done won't.
 | 
			
		||||
 | 
			
		||||
[Operator] overloading also impacts [script optimization] when using [`OptimizationLevel::Full`].
 | 
			
		||||
See the section on [script optimization] for more details.
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										34
									
								
								_archive/rhai_engine/rhaibook/rust/overloading.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								_archive/rhai_engine/rhaibook/rust/overloading.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,34 @@
 | 
			
		||||
Function Overloading
 | 
			
		||||
====================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Functions registered with the [`Engine`] can be _overloaded_ as long as the _signature_ is unique,
 | 
			
		||||
i.e. different functions can have the same name as long as their parameters are of different numbers
 | 
			
		||||
(i.e. _arity_) or  different types.
 | 
			
		||||
 | 
			
		||||
New definitions _overwrite_ previous definitions of the same name, same arity and same parameter types.
 | 
			
		||||
 | 
			
		||||
~~~admonish tip "Tip: Overloading as a form of default parameter values"
 | 
			
		||||
 | 
			
		||||
Rhai does not support default values for function parameters.
 | 
			
		||||
 | 
			
		||||
However it is extremely easy to _simulate_ default parameter values via multiple overloaded
 | 
			
		||||
registrations of the same function name.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// The following definition of 'foo' is equivalent to the pseudo-code:
 | 
			
		||||
//   fn foo(x = 42_i64, y = "hello", z = true) -> i64 { ... }
 | 
			
		||||
 | 
			
		||||
fn foo3(x: i64, y: &str, z: bool) -> i64 { ... }
 | 
			
		||||
fn foo2(x: i64, y: &str) -> i64 { foo3(x, y, true) }
 | 
			
		||||
fn foo1(x: i64) -> i64 { foo2(x, "hello") }
 | 
			
		||||
fn foo0() -> i64 { foo1(42) }
 | 
			
		||||
 | 
			
		||||
engine.register_fn("foo", foo0)     // no parameters
 | 
			
		||||
      .register_fn("foo", foo1)     // 1 parameter
 | 
			
		||||
      .register_fn("foo", foo2)     // 2 parameters
 | 
			
		||||
      .register_fn("foo", foo3);    // 3 parameters
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										55
									
								
								_archive/rhai_engine/rhaibook/rust/override.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								_archive/rhai_engine/rhaibook/rust/override.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,55 @@
 | 
			
		||||
Override a Built-in Function
 | 
			
		||||
============================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Any similarly-named function defined in a script _overrides_ any built-in or registered
 | 
			
		||||
native Rust function of the same name and number of parameters.
 | 
			
		||||
 | 
			
		||||
```js
 | 
			
		||||
// Override the built-in function 'to_float' when called as a method
 | 
			
		||||
fn to_float() {
 | 
			
		||||
    print(`Ha! Gotcha! ${this}`);
 | 
			
		||||
    42.0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let x = 123.to_float();
 | 
			
		||||
 | 
			
		||||
print(x);       // what happens?
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Monkey patching Rhai"
 | 
			
		||||
 | 
			
		||||
Most of Rhai's built-in functionality resides in registered functions.
 | 
			
		||||
 | 
			
		||||
If you dislike any built-in function, simply provide your own implementation to
 | 
			
		||||
_override_ the built-in version.
 | 
			
		||||
 | 
			
		||||
The ability to modify the operating environment dynamically at runtime is called
 | 
			
		||||
"[monkey patching](https://en.wikipedia.org/wiki/Monkey_patch)."
 | 
			
		||||
It is rarely recommended, but if you need it, you need it bad.
 | 
			
		||||
 | 
			
		||||
In other words, do it only when _all else fails_.  Do not monkey patch Rhai simply
 | 
			
		||||
because you _can_.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish info.small "Search order for functions"
 | 
			
		||||
 | 
			
		||||
Rhai searches for the correct implementation of a function in the following order:
 | 
			
		||||
 | 
			
		||||
1. Rhai script-defined [functions],
 | 
			
		||||
 | 
			
		||||
2. Native Rust functions registered directly via the `Engine::register_XXX` API,
 | 
			
		||||
 | 
			
		||||
3. Native Rust functions in [packages] that have been loaded via `Engine::register_global_module`,
 | 
			
		||||
 | 
			
		||||
4. Native Rust or Rhai script-defined functions in [imported][`import`] [modules] that are exposed to
 | 
			
		||||
   the global [namespace][function namespace] (e.g. via the `#[rhai_fn(global)]` attribute in a
 | 
			
		||||
   [plugin module]),
 | 
			
		||||
 | 
			
		||||
5. Native Rust or Rhai script-defined functions in [modules] loaded via
 | 
			
		||||
   `Engine::register_static_module` that are exposed to the global [namespace][function namespace]
 | 
			
		||||
   (e.g. via the `#[rhai_fn(global)]` attribute in a [plugin module]),
 | 
			
		||||
 | 
			
		||||
6. [Built-in][built-in operators] functions.
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										44
									
								
								_archive/rhai_engine/rhaibook/rust/packages/builtin.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								_archive/rhai_engine/rhaibook/rust/packages/builtin.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
Built-In Packages
 | 
			
		||||
=================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
`Engine::new` creates an [`Engine`] with the `StandardPackage` loaded.
 | 
			
		||||
 | 
			
		||||
`Engine::new_raw` creates an [`Engine`] with _no_ [package] loaded.
 | 
			
		||||
 | 
			
		||||
| Package                | Description                                                                                                 | In `Core` | In `Standard` |
 | 
			
		||||
| ---------------------- | ----------------------------------------------------------------------------------------------------------- | :-------: | :-----------: |
 | 
			
		||||
| `LanguageCorePackage`  | core functions for the Rhai language                                                                        |    yes    |      yes      |
 | 
			
		||||
| `ArithmeticPackage`    | arithmetic operators (e.g. `+`, `-`, `*`, `/`) for numeric types that are not built in (e.g. `u16`)         |    yes    |      yes      |
 | 
			
		||||
| `BitFieldPackage`      | basic [bit-field] functions                                                                                 |  **no**   |      yes      |
 | 
			
		||||
| `BasicIteratorPackage` | numeric ranges (e.g. `range(1, 100, 5)`), iterators for [arrays], [strings], [bit-fields] and [object maps] |    yes    |      yes      |
 | 
			
		||||
| `LogicPackage`         | logical and comparison operators (e.g. `==`, `>`) for numeric types that are not built in (e.g. `u16`)      |  **no**   |      yes      |
 | 
			
		||||
| `BasicStringPackage`   | basic string functions (e.g. `print`, `debug`, `len`) that are not built in                                 |    yes    |      yes      |
 | 
			
		||||
| `BasicTimePackage`     | basic time functions (e.g. [timestamps], not available under [`no_time`] or [`no_std`])                     |  **no**   |      yes      |
 | 
			
		||||
| `MoreStringPackage`    | additional string functions, including converting common types to string                                    |  **no**   |      yes      |
 | 
			
		||||
| `BasicMathPackage`     | basic math functions (e.g. `sin`, `sqrt`)                                                                   |  **no**   |      yes      |
 | 
			
		||||
| `BasicArrayPackage`    | basic [array] functions (not available under [`no_index`])                                                  |  **no**   |      yes      |
 | 
			
		||||
| `BasicBlobPackage`     | basic [BLOB] functions (not available under [`no_index`])                                                   |  **no**   |      yes      |
 | 
			
		||||
| `BasicMapPackage`      | basic [object map] functions (not available under [`no_object`])                                            |  **no**   |      yes      |
 | 
			
		||||
| `BasicFnPackage`       | basic methods for [function pointers]                                                                       |    yes    |      yes      |
 | 
			
		||||
| `DebuggingPackage`     | basic functions for [debugging][debugger] (requires [`debugging`])                                          |    yes    |      yes      |
 | 
			
		||||
| `CorePackage`          | basic essentials                                                                                            |    yes    |      yes      |
 | 
			
		||||
| `StandardPackage`      | standard library (default for `Engine::new`)                                                                |  **no**   |      yes      |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`CorePackage`
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
If only minimal functionalities are required, register the `CorePackage` instead.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::Engine;
 | 
			
		||||
use rhai::packages::{Package, CorePackage};
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new_raw();
 | 
			
		||||
let package = CorePackage::new();
 | 
			
		||||
 | 
			
		||||
// Register the package into the 'Engine'.
 | 
			
		||||
package.register_into_engine(&mut engine);
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										69
									
								
								_archive/rhai_engine/rhaibook/rust/packages/crate.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								_archive/rhai_engine/rhaibook/rust/packages/crate.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
			
		||||
Create a Custom Package as an Independent Crate
 | 
			
		||||
===============================================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
Creating a custom [package] as an independent crate allows it to be shared by multiple projects.
 | 
			
		||||
 | 
			
		||||
```admonish abstract.small "Key concepts"
 | 
			
		||||
 | 
			
		||||
* Create a Rust crate that specifies [`rhai`](https://crates.io/crates/rhai) as dependency.
 | 
			
		||||
 | 
			
		||||
* The main `lib.rs` module can contain the [package] being constructed.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish example.small
 | 
			
		||||
The projects [`rhai-rand`] and [`rhai-sci`] show simple examples of creating a custom [package]
 | 
			
		||||
as an independent crate.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Implementation
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
`Cargo.toml`:
 | 
			
		||||
 | 
			
		||||
```toml
 | 
			
		||||
[package]
 | 
			
		||||
name = "my-package"     # 'my-package' crate
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
rhai = "{{version}}"    # assuming {{version}} is the latest version
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`lib.rs`:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::def_package;
 | 
			
		||||
use rhai::plugin::*;
 | 
			
		||||
 | 
			
		||||
// This is a plugin module
 | 
			
		||||
#[export_module]
 | 
			
		||||
mod my_module {
 | 
			
		||||
    // Constants are ignored when used as a package
 | 
			
		||||
    pub const MY_NUMBER: i64 = 42;
 | 
			
		||||
 | 
			
		||||
    pub fn greet(name: &str) -> String {
 | 
			
		||||
        format!("hello, {}!", name)
 | 
			
		||||
    }
 | 
			
		||||
    pub fn get_num() -> i64 {
 | 
			
		||||
        42
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // This is a sub-module, but if using combine_with_exported_module!, it will
 | 
			
		||||
    // be flattened and all functions registered at the top level.
 | 
			
		||||
    pub mod my_sub_module {
 | 
			
		||||
        pub fn get_sub_num() -> i64 {
 | 
			
		||||
            0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Define the package 'MyPackage' which is exported for the crate.
 | 
			
		||||
def_package! {
 | 
			
		||||
    /// My own personal super package in a new crate!
 | 
			
		||||
    pub MyPackage(module) {
 | 
			
		||||
        combine_with_exported_module!(module, "my-functions", my_module);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										256
									
								
								_archive/rhai_engine/rhaibook/rust/packages/create.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								_archive/rhai_engine/rhaibook/rust/packages/create.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,256 @@
 | 
			
		||||
Create a Custom Package
 | 
			
		||||
=======================
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
```admonish info.side "See also"
 | 
			
		||||
 | 
			
		||||
See also the [_One Engine Instance Per Call_]({{rootUrl}}/patterns/parallel.md) pattern.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The macro `def_package!` can be used to create a custom [package].
 | 
			
		||||
 | 
			
		||||
A custom [package] can aggregate many other [packages] into a single self-contained unit.
 | 
			
		||||
More functions can be added on top of others.
 | 
			
		||||
 | 
			
		||||
Custom [packages] are extremely useful when multiple [raw `Engine`] instances must be created such
 | 
			
		||||
that they all share the same set of functions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`def_package!`
 | 
			
		||||
--------------
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> def_package! {
 | 
			
		||||
>     /// Package description doc-comment
 | 
			
		||||
>     pub name(variable) {
 | 
			
		||||
>                         :
 | 
			
		||||
>         // package init code block
 | 
			
		||||
>                         :
 | 
			
		||||
>     }
 | 
			
		||||
>
 | 
			
		||||
>     // Multiple packages can be defined at the same time,
 | 
			
		||||
>     // possibly with base packages and/or code to setup an Engine.
 | 
			
		||||
>
 | 
			
		||||
>     /// Package description doc-comment
 | 
			
		||||
>     pub(crate) name(variable) : base_package_1, base_package_2, ... {
 | 
			
		||||
>                         :
 | 
			
		||||
>         // package init code block
 | 
			
		||||
>                         :
 | 
			
		||||
>     } |> |engine| {
 | 
			
		||||
>                         :
 | 
			
		||||
>         // engine setup code block
 | 
			
		||||
>                         :
 | 
			
		||||
>     }
 | 
			
		||||
> 
 | 
			
		||||
>     /// A private package description doc-comment
 | 
			
		||||
>     name(variable) {
 | 
			
		||||
>                         :
 | 
			
		||||
>         // private package init code block
 | 
			
		||||
>                         :
 | 
			
		||||
>     }
 | 
			
		||||
>
 | 
			
		||||
>     :
 | 
			
		||||
> }
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
where:
 | 
			
		||||
 | 
			
		||||
|         Element         | Description                                                                                          |
 | 
			
		||||
| :---------------------: | ---------------------------------------------------------------------------------------------------- |
 | 
			
		||||
|       description       | doc-comment for the [package]                                                                        |
 | 
			
		||||
|       `pub` etc.        | visibility of the [package]                                                                          |
 | 
			
		||||
|          name           | name of the [package], usually ending in ...`Package`                                                |
 | 
			
		||||
|        variable         | a variable name holding a reference to the [module] forming the [package], usually `module` or `lib` |
 | 
			
		||||
|      base_package       | an external [package] type that is merged into this [package] as a dependency                        |
 | 
			
		||||
| package init code block | a code block that initializes the [package]                                                          |
 | 
			
		||||
|         engine          | a variable name holding a mutable reference to an [`Engine`]                                         |
 | 
			
		||||
| engine setup code block | a code block that performs setup tasks on an [`Engine`] during registration                          |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Examples
 | 
			
		||||
--------
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Import necessary types and traits.
 | 
			
		||||
use rhai::def_package;      // 'def_package!' macro
 | 
			
		||||
use rhai::packages::{ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage};
 | 
			
		||||
use rhai::{FuncRegistration, CustomType, TypeBuilder};
 | 
			
		||||
 | 
			
		||||
/// This is a custom type.
 | 
			
		||||
#[derive(Clone, CustomType)]
 | 
			
		||||
struct TestStruct {
 | 
			
		||||
    foo: String,
 | 
			
		||||
    bar: i64,
 | 
			
		||||
    baz: bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def_package! {
 | 
			
		||||
    /// My own personal super package
 | 
			
		||||
    // Aggregate other base packages (if any) simply by listing them after a colon.
 | 
			
		||||
    pub MyPackage(module) : ArithmeticPackage, LogicPackage, BasicArrayPackage, BasicMapPackage
 | 
			
		||||
    {
 | 
			
		||||
        // Register additional Rust function.
 | 
			
		||||
        FuncRegistration::new("get_bar_value")
 | 
			
		||||
            .with_params_info(&["s: &mut TestStruct", "i64"])
 | 
			
		||||
            .set_into_module(module, |s: &mut TestStruct| s.bar);
 | 
			
		||||
 | 
			
		||||
        // Register a function for use as a custom operator.
 | 
			
		||||
        FuncRegistration::new("@")
 | 
			
		||||
            .with_namespace(FnNamespace::Global)    // <- make it available globally.
 | 
			
		||||
            .set_into_module(module, |x: i64, y: i64| x * x + y * y);
 | 
			
		||||
    } |> |engine| {
 | 
			
		||||
        // This optional block performs tasks on an 'Engine' instance,
 | 
			
		||||
        // e.g. register custom types and/or custom operators/syntax.
 | 
			
		||||
 | 
			
		||||
        // Register custom type.
 | 
			
		||||
        engine.build_type::<TestStruct>();
 | 
			
		||||
 | 
			
		||||
        // Define a custom operator '@' with precedence of 160
 | 
			
		||||
        // (i.e. between +|- and *|/).
 | 
			
		||||
        engine.register_custom_operator("@", 160).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: Feature gates on base packages"
 | 
			
		||||
 | 
			
		||||
Base packages in the list after the colon (`:`) can also have attributes (such as feature gates)!
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
def_package! {
 | 
			
		||||
    // 'BasicArrayPackage' is used only under 'arrays' feature.
 | 
			
		||||
    pub MyPackage(module) :
 | 
			
		||||
            ArithmeticPackage,
 | 
			
		||||
            LogicPackage,
 | 
			
		||||
            #[cfg(feature = "arrays")]
 | 
			
		||||
            BasicArrayPackage
 | 
			
		||||
    {
 | 
			
		||||
        ...
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
~~~admonish danger.small "Advanced: `Engine` setup with `|>`"
 | 
			
		||||
 | 
			
		||||
A second code block (in the syntax of a [closure]) following a right-triangle symbol (`|>`)
 | 
			
		||||
is run whenever the [package] is being registered.
 | 
			
		||||
 | 
			
		||||
It allows performing setup tasks directly on that [`Engine`], e.g. registering [custom types],
 | 
			
		||||
[custom operators] and/or [custom syntax].
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
def_package! {
 | 
			
		||||
    pub MyPackage(module) {
 | 
			
		||||
            :
 | 
			
		||||
            :
 | 
			
		||||
    } |> |engine| {
 | 
			
		||||
        // Call methods on 'engine'
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Create a Custom Package from a Plugin Module
 | 
			
		||||
--------------------------------------------
 | 
			
		||||
 | 
			
		||||
```admonish question.side "Trivia"
 | 
			
		||||
 | 
			
		||||
This is exactly how Rhai's built-in [packages], such as `BasicMathPackage`, are actually implemented.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
By far the easiest way to create a custom [package] is to call `plugin::combine_with_exported_module!`
 | 
			
		||||
from within `def_package!` which simply merges in all the functions defined within a [plugin module].
 | 
			
		||||
 | 
			
		||||
Due to specific requirements of a [package], `plugin::combine_with_exported_module!`
 | 
			
		||||
_flattens_ all sub-modules (i.e. all functions and [type iterators] defined within sub-modules
 | 
			
		||||
are pulled up to the top level instead) and so there will not be any sub-modules added to the [package].
 | 
			
		||||
 | 
			
		||||
Variables in the [plugin module] are ignored.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Import necessary types and traits.
 | 
			
		||||
use rhai::def_package;
 | 
			
		||||
use rhai::packages::{ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage};
 | 
			
		||||
use rhai::plugin::*;
 | 
			
		||||
 | 
			
		||||
// Define plugin module.
 | 
			
		||||
#[export_module]
 | 
			
		||||
mod my_plugin_module {
 | 
			
		||||
    // Custom type.
 | 
			
		||||
    pub type ABC = TestStruct;
 | 
			
		||||
 | 
			
		||||
    // Public constant.
 | 
			
		||||
    pub const MY_NUMBER: i64 = 42;
 | 
			
		||||
 | 
			
		||||
    // Public function.
 | 
			
		||||
    pub fn greet(name: &str) -> String {
 | 
			
		||||
        format!("hello, {}!", name)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Non-public functions are by default not exported.
 | 
			
		||||
    fn get_private_num() -> i64 {
 | 
			
		||||
        42
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Public function.
 | 
			
		||||
    pub fn get_num() -> i64 {
 | 
			
		||||
        get_private_num()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Custom operator.
 | 
			
		||||
    #[rhai_fn(name = "@")]
 | 
			
		||||
    pub fn square_add(x: i64, y: i64) -> i64 {
 | 
			
		||||
        x * x + y * y
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // A sub-module.  If using 'combine_with_exported_module!', however,
 | 
			
		||||
    // it will be flattened and all functions registered at the top level.
 | 
			
		||||
    //
 | 
			
		||||
    // Because of this flattening, sub-modules are very convenient for
 | 
			
		||||
    // putting feature gates onto large groups of functions.
 | 
			
		||||
    #[cfg(feature = "sub-num-feature")]
 | 
			
		||||
    pub mod my_sub_module {
 | 
			
		||||
        // Only available under 'sub-num-feature'.
 | 
			
		||||
        pub fn get_sub_num() -> i64 {
 | 
			
		||||
            0
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
def_package! {
 | 
			
		||||
    /// My own personal super package
 | 
			
		||||
    // Aggregate other base packages (if any) simply by listing them after a colon.
 | 
			
		||||
    pub MyPackage(module) : ArithmeticPackage, LogicPackage, BasicArrayPackage, BasicMapPackage
 | 
			
		||||
    {
 | 
			
		||||
        // Merge all registered functions and constants from the plugin module
 | 
			
		||||
        // into the custom package.
 | 
			
		||||
        //
 | 
			
		||||
        // The sub-module 'my_sub_module' is flattened and its functions
 | 
			
		||||
        // registered at the top level.
 | 
			
		||||
        //
 | 
			
		||||
        // The text string name in the second parameter can be anything
 | 
			
		||||
        // and is reserved for future use; it is recommended to be an
 | 
			
		||||
        // ID string that uniquely identifies the plugin module.
 | 
			
		||||
        //
 | 
			
		||||
        // The constant variable, 'MY_NUMBER', is ignored.
 | 
			
		||||
        //
 | 
			
		||||
        // This call ends up registering three functions at the top level of
 | 
			
		||||
        // the package:
 | 
			
		||||
        // 1) 'greet'
 | 
			
		||||
        // 2) 'get_num'
 | 
			
		||||
        // 3) 'get_sub_num' (flattened from 'my_sub_module')
 | 
			
		||||
        //
 | 
			
		||||
        combine_with_exported_module!(module, "my-mod", my_plugin_module));
 | 
			
		||||
    } |> |engine| {
 | 
			
		||||
        // This optional block is used to set up an 'Engine' during registration.
 | 
			
		||||
 | 
			
		||||
        // Define a custom operator '@' with precedence of 160
 | 
			
		||||
        // (i.e. between +|- and *|/).
 | 
			
		||||
        engine.register_custom_operator("@", 160).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										60
									
								
								_archive/rhai_engine/rhaibook/rust/packages/index.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								_archive/rhai_engine/rhaibook/rust/packages/index.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
Packages
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
{{#include ../../links.md}}
 | 
			
		||||
 | 
			
		||||
The built-in library of Rhai is provided as various _packages_ that can be turned into _shared_
 | 
			
		||||
[modules], which in turn can be registered into the _global namespace_ of an [`Engine`] via
 | 
			
		||||
`Engine::register_global_module`.
 | 
			
		||||
 | 
			
		||||
Packages reside under `rhai::packages::*` and the trait `rhai::packages::Package` must be loaded in
 | 
			
		||||
order for packages to be used.
 | 
			
		||||
 | 
			
		||||
```admonish question.small "Trivia: Packages _are_ modules!"
 | 
			
		||||
 | 
			
		||||
Internally, a _package_ is a [module], with some conveniences to make it easier to define and use as
 | 
			
		||||
a standard _library_ for an [`Engine`].
 | 
			
		||||
 | 
			
		||||
Packages typically contain Rust functions that are callable within a Rhai script.
 | 
			
		||||
All _top-level_ functions in a package are available under the _global namespace_
 | 
			
		||||
(i.e. they're available without namespace qualifiers).
 | 
			
		||||
 | 
			
		||||
Sub-[modules] and [variables] are ignored in packages.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Share a Package Among Multiple `Engine`'s
 | 
			
		||||
-----------------------------------------
 | 
			
		||||
 | 
			
		||||
`Engine::register_global_module` and `Engine::register_static_module` both require _shared_ [modules].
 | 
			
		||||
 | 
			
		||||
Once a package is created (e.g. via `Package::new`), it can be registered into multiple instances of
 | 
			
		||||
[`Engine`], even across threads (under the [`sync`] feature).
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Sharing package"
 | 
			
		||||
 | 
			
		||||
A package only has to be created _once_ and essentially shared among multiple [`Engine`] instances.
 | 
			
		||||
 | 
			
		||||
This is particularly useful when spawning large number of [raw `Engine`'s][raw `Engine`].
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::Engine;
 | 
			
		||||
use rhai::packages::Package         // load the 'Package' trait to use packages
 | 
			
		||||
use rhai::packages::CorePackage;    // the 'core' package contains basic functionalities (e.g. arithmetic)
 | 
			
		||||
 | 
			
		||||
// Create a package - can be shared among multiple 'Engine' instances
 | 
			
		||||
let package = CorePackage::new();
 | 
			
		||||
 | 
			
		||||
let mut engines_collection: Vec<Engine> = Vec::new();
 | 
			
		||||
 | 
			
		||||
// Create 100 'raw' Engines
 | 
			
		||||
for _ in 0..100 {
 | 
			
		||||
    let mut engine = Engine::new_raw();
 | 
			
		||||
 | 
			
		||||
    // Register the package into the global namespace.
 | 
			
		||||
    package.register_into_engine(&mut engine);
 | 
			
		||||
 | 
			
		||||
    engines_collection.push(engine);
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										40
									
								
								_archive/rhai_engine/rhaibook/rust/print-custom.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								_archive/rhai_engine/rhaibook/rust/print-custom.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,40 @@
 | 
			
		||||
Printing for Custom Types
 | 
			
		||||
=========================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Provide These Functions
 | 
			
		||||
-----------------------
 | 
			
		||||
 | 
			
		||||
To use [custom types] for [`print`] and [`debug`], or convert a [custom type] into a [string],
 | 
			
		||||
it is necessary that the following functions, at minimum, be registered (assuming the [custom type]
 | 
			
		||||
is `T: Display + Debug`).
 | 
			
		||||
 | 
			
		||||
| Function    | Signature                            | Typical implementation | Usage                                                      |
 | 
			
		||||
| ----------- | ------------------------------------ | ---------------------- | ---------------------------------------------------------- |
 | 
			
		||||
| `to_string` | <code>\|x: &mut T\| -> String</code> | `x.to_string()`        | converts the [custom type] into a [string]                 |
 | 
			
		||||
| `to_debug`  | <code>\|x: &mut T\| -> String</code> | `format!("{x:?}")`     | converts the [custom type] into a [string] in debug format |
 | 
			
		||||
 | 
			
		||||
~~~admonish tip.small "Tip: `#[rhai_fn(global)]`"
 | 
			
		||||
 | 
			
		||||
If these functions are defined via a [plugin module], be sure to include the `#[rhai_fn(global)]` attribute
 | 
			
		||||
in order to make them available globally.
 | 
			
		||||
 | 
			
		||||
See [this section]({{rootUrl}}/plugins/module.md#use-rhai_fnglobal) for more details.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Also Consider These
 | 
			
		||||
-------------------
 | 
			
		||||
 | 
			
		||||
The following functions are implemented using `to_string` or `to_debug` by default, but can be
 | 
			
		||||
overloaded with custom versions.
 | 
			
		||||
 | 
			
		||||
| Function      | Signature                                      | Default     | Usage                                                                  |
 | 
			
		||||
| ------------- | ---------------------------------------------- | ----------- | ---------------------------------------------------------------------- |
 | 
			
		||||
| `print`       | <code>\|x: &mut T\| -> String</code>           | `to_string` | converts the [custom type] into a [string] for the [`print`] statement |
 | 
			
		||||
| `debug`       | <code>\|x: &mut T\| -> String</code>           | `to_debug`  | converts the [custom type] into a [string] for the [`debug`] statement |
 | 
			
		||||
| `+` operator  | <code>\|s: &str, x: T\| -> String</code>       | `to_string` | concatenates the [custom type] with another [string]                   |
 | 
			
		||||
| `+` operator  | <code>\|x: &mut T, s: &str\| -> String</code>  | `to_string` | concatenates another [string] with the [custom type]                   |
 | 
			
		||||
| `+=` operator | <code>\|s: &mut ImmutableString, x: T\|</code> | `to_string` | appends the [custom type] to an existing [string]                      |
 | 
			
		||||
							
								
								
									
										105
									
								
								_archive/rhai_engine/rhaibook/rust/reg-custom-type.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								_archive/rhai_engine/rhaibook/rust/reg-custom-type.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,105 @@
 | 
			
		||||
Manually Register Custom Type
 | 
			
		||||
=============================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Warning"
 | 
			
		||||
 | 
			
		||||
This assumes that the type is defined in an external crate and so the [`CustomType`] trait
 | 
			
		||||
cannot be implemented for it due to Rust's [_orphan rule_](https://doc.rust-lang.org/book/ch10-02-traits.html).
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.side "Tip: Working with enums"
 | 
			
		||||
 | 
			
		||||
It is also possible to use Rust enums with Rhai.
 | 
			
		||||
 | 
			
		||||
See the pattern [Working with Enums]({{rootUrl}}/patterns/enums.md) for more details.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
The custom type needs to be _registered_ into an [`Engine`] via:
 | 
			
		||||
 | 
			
		||||
| `Engine` API                   | `type_of` output    |
 | 
			
		||||
| ------------------------------ | ------------------- |
 | 
			
		||||
| `register_type::<T>`           | full Rust path name |
 | 
			
		||||
| `register_type_with_name::<T>` | friendly name       |
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, EvalAltResult};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone)]
 | 
			
		||||
struct TestStruct {
 | 
			
		||||
    field: i64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TestStruct {
 | 
			
		||||
    fn new() -> Self {
 | 
			
		||||
        Self { field: 1 }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Register custom type with friendly name
 | 
			
		||||
engine.register_type_with_name::<TestStruct>("TestStruct")
 | 
			
		||||
      .register_fn("new_ts", TestStruct::new);
 | 
			
		||||
 | 
			
		||||
// Cast result back to custom type.
 | 
			
		||||
let result = engine.eval::<TestStruct>(
 | 
			
		||||
"
 | 
			
		||||
    new_ts()        // calls 'TestStruct::new'
 | 
			
		||||
")?;
 | 
			
		||||
 | 
			
		||||
println!("result: {}", result.field);   // prints 1
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
`type_of()` a Custom Type
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
```admonish question.side.wide "Giving types the same name?"
 | 
			
		||||
 | 
			
		||||
It is OK to register several custom types under the _same_ friendly name
 | 
			
		||||
and `type_of()` will faithfully return it.
 | 
			
		||||
 | 
			
		||||
How this might possibly be useful is left to the imagination of the user.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[`type_of()`] works fine with custom types and returns the name of the type.
 | 
			
		||||
 | 
			
		||||
If `Engine::register_type_with_name` is used to register the custom type with a special
 | 
			
		||||
"pretty-print" friendly name, [`type_of()`] will return that name instead.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
engine.register_type::<TestStruct1>()
 | 
			
		||||
      .register_fn("new_ts1", TestStruct1::new)
 | 
			
		||||
      .register_type_with_name::<TestStruct2>("TestStruct")
 | 
			
		||||
      .register_fn("new_ts2", TestStruct2::new);
 | 
			
		||||
 | 
			
		||||
let ts1_type = engine.eval::<String>("let x = new_ts1(); x.type_of()")?;
 | 
			
		||||
let ts2_type = engine.eval::<String>("let x = new_ts2(); x.type_of()")?;
 | 
			
		||||
 | 
			
		||||
println!("{ts1_type}");                 // prints 'path::to::TestStruct'
 | 
			
		||||
println!("{ts2_type}");                 // prints 'TestStruct'
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`==` Operator
 | 
			
		||||
-------------
 | 
			
		||||
 | 
			
		||||
Many standard functions (e.g. filtering, searching and sorting) expect a custom type to be
 | 
			
		||||
_comparable_, meaning that the `==` operator must be registered for the custom type.
 | 
			
		||||
 | 
			
		||||
For example, in order to use the [`in`] operator with a custom type for an [array],
 | 
			
		||||
the `==` operator is used to check whether two values are the same.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Assume 'TestStruct' implements `PartialEq`
 | 
			
		||||
engine.register_fn("==",
 | 
			
		||||
    |item1: &mut TestStruct, item2: TestStruct| item1 == &item2
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// Then this works in Rhai:
 | 
			
		||||
let item = new_ts();        // construct a new 'TestStruct'
 | 
			
		||||
item in array;              // 'in' operator uses '=='
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										193
									
								
								_archive/rhai_engine/rhaibook/rust/register-raw.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										193
									
								
								_archive/rhai_engine/rhaibook/rust/register-raw.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,193 @@
 | 
			
		||||
Use the Low-Level API to Register a Rust Function
 | 
			
		||||
=================================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
When a native Rust function is registered with an [`Engine`] using the `register_XXX` API, Rhai
 | 
			
		||||
transparently converts all function arguments from [`Dynamic`] into the correct types before calling
 | 
			
		||||
the function.
 | 
			
		||||
 | 
			
		||||
For more power and flexibility, there is a _low-level_ API to work directly with [`Dynamic`] values
 | 
			
		||||
without the conversions.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Raw Function Registration
 | 
			
		||||
-------------------------
 | 
			
		||||
 | 
			
		||||
The `Engine::register_raw_fn` method is marked _volatile_, meaning that it may be changed without warning.
 | 
			
		||||
 | 
			
		||||
If this is acceptable, then using this method to register a Rust function opens up more opportunities.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
engine.register_raw_fn(
 | 
			
		||||
    "increment_by",                                         // function name
 | 
			
		||||
    &[                                                      // a slice containing parameter types
 | 
			
		||||
        std::any::TypeId::of::<i64>(),                      // type of first parameter
 | 
			
		||||
        std::any::TypeId::of::<i64>()                       // type of second parameter
 | 
			
		||||
    ],
 | 
			
		||||
    |context, args| {                                       // fixed function signature
 | 
			
		||||
        // Arguments are guaranteed to be correct in number and of the correct types.
 | 
			
		||||
 | 
			
		||||
        // But remember this is Rust, so you can keep only one mutable reference at any one time!
 | 
			
		||||
        // Therefore, get a '&mut' reference to the first argument _last_.
 | 
			
		||||
        // Alternatively, use `args.split_first_mut()` etc. to split the slice first.
 | 
			
		||||
 | 
			
		||||
        let y = *args[1].read_lock::<i64>().unwrap();       // get a reference to the second argument
 | 
			
		||||
                                                            // then copy it because it is a primary type
 | 
			
		||||
 | 
			
		||||
        let y = args[1].take().cast::<i64>();               // alternatively, directly 'consume' it
 | 
			
		||||
 | 
			
		||||
        let y = args[1].as_int().unwrap();                  // alternatively, use 'as_xxx()'
 | 
			
		||||
 | 
			
		||||
        let x = args[0].write_lock::<i64>().unwrap();       // get a '&mut' reference to the first argument
 | 
			
		||||
 | 
			
		||||
        *x += y;                                            // perform the action
 | 
			
		||||
 | 
			
		||||
        Ok(Dynamic::UNIT)                                   // must be 'Result<Dynamic, Box<EvalAltResult>>'
 | 
			
		||||
    }
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// The above is the same as (in fact, internally they are equivalent):
 | 
			
		||||
 | 
			
		||||
engine.register_fn("increment_by", |x: &mut i64, y: i64| *x += y);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Function Signature
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
The function signature passed to `Engine::register_raw_fn` takes the following form.
 | 
			
		||||
 | 
			
		||||
> ```rust
 | 
			
		||||
> Fn(context: NativeCallContext, args: &mut [&mut Dynamic]) -> Result<T, Box<EvalAltResult>>
 | 
			
		||||
> ```
 | 
			
		||||
 | 
			
		||||
where:
 | 
			
		||||
 | 
			
		||||
| Parameter |         Type          | Description                                                                                                                                 |
 | 
			
		||||
| --------- | :-------------------: | ------------------------------------------------------------------------------------------------------------------------------------------- |
 | 
			
		||||
| `T`       |     `impl Clone`      | return type of the function                                                                                                                 |
 | 
			
		||||
| `context` | [`NativeCallContext`] | the current _native call context_, useful for recursively calling functions on the same [`Engine`]                                          |
 | 
			
		||||
| `args`    | `&mut [&mut Dynamic]` | a slice containing `&mut` references to [`Dynamic`] values.<br/>The slice is guaranteed to contain enough arguments _of the correct types_. |
 | 
			
		||||
 | 
			
		||||
### Return value
 | 
			
		||||
 | 
			
		||||
The return value is the result of the function call.
 | 
			
		||||
 | 
			
		||||
Remember, in Rhai, all arguments _except_ the _first_ one are always passed by _value_ (i.e. cloned).
 | 
			
		||||
Therefore, it is unnecessary to ever mutate any argument except the first one, as all mutations
 | 
			
		||||
will be on the cloned copy.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Extract The First `&mut` Argument (If Any)
 | 
			
		||||
------------------------------------------
 | 
			
		||||
 | 
			
		||||
To extract the first `&mut` argument passed by reference from the `args` parameter (`&mut [&mut Dynamic]`),
 | 
			
		||||
use the following to get a mutable reference to the underlying value:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let value: &mut T = &mut *args[0].write_lock::<T>().unwrap();
 | 
			
		||||
 | 
			
		||||
*value = ...    // overwrite the existing value of the first `&mut` parameter
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
When there is a mutable reference to the first `&mut` argument, there can be no other immutable
 | 
			
		||||
references to `args`, otherwise the Rust borrow checker will complain.
 | 
			
		||||
 | 
			
		||||
Therefore, always extract the mutable reference last, _after_ all other arguments are taken.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Extract Other Pass-By-Value Arguments
 | 
			
		||||
-------------------------------------
 | 
			
		||||
 | 
			
		||||
To extract an argument passed by value from the `args` parameter (`&mut [&mut Dynamic]`), use the following statements.
 | 
			
		||||
 | 
			
		||||
| Argument type             | Access statement (`n` = argument position)     |                 Result                  | Original value |
 | 
			
		||||
| ------------------------- | ---------------------------------------------- | :-------------------------------------: | :------------: |
 | 
			
		||||
| `INT`                     | `args[n].as_int().unwrap()`                    |                  `INT`                  |   untouched    |
 | 
			
		||||
| `FLOAT`                   | `args[n].as_float().unwrap()`                  |                 `FLOAT`                 |   untouched    |
 | 
			
		||||
| [`Decimal`][rust_decimal] | `args[n].as_decimal().unwrap()`                |        [`Decimal`][rust_decimal]        |   untouched    |
 | 
			
		||||
| `bool`                    | `args[n].as_bool().unwrap()`                   |                 `bool`                  |   untouched    |
 | 
			
		||||
| `char`                    | `args[n].as_char().unwrap()`                   |                 `char`                  |   untouched    |
 | 
			
		||||
| `()`                      | `args[n].as_unit().unwrap()`                   |                  `()`                   |   untouched    |
 | 
			
		||||
| [String]                  | `&*args[n].as_immutable_string_ref().unwrap()` | [`&ImmutableString`][`ImmutableString`] |   untouched    |
 | 
			
		||||
| [String] (consumed)       | `args[n].take().cast::<ImmutableString>()`     |           [`ImmutableString`]           |     [`()`]     |
 | 
			
		||||
| Others                    | `&*args[n].read_lock::<T>().unwrap()`          |                  `&T`                   |   untouched    |
 | 
			
		||||
| Others (consumed)         | `args[n].take().cast::<T>()`                   |                   `T`                   |     [`()`]     |
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Example – Pass a Callback to a Rust Function
 | 
			
		||||
--------------------------------------------------
 | 
			
		||||
 | 
			
		||||
The low-level API is useful when there is a need to interact with the scripting [`Engine`]
 | 
			
		||||
within a function.
 | 
			
		||||
 | 
			
		||||
The following example registers a function that takes a [function pointer] as an argument,
 | 
			
		||||
then calls it within the same [`Engine`].  This way, a _callback_ function can be provided
 | 
			
		||||
to a native Rust function.
 | 
			
		||||
 | 
			
		||||
The example also showcases the use of `FnPtr::call_raw`, a low-level API which allows binding the
 | 
			
		||||
`this` pointer to the function pointer call.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, FnPtr};
 | 
			
		||||
 | 
			
		||||
let mut engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
// Register a Rust function
 | 
			
		||||
engine.register_raw_fn(
 | 
			
		||||
    "bar",
 | 
			
		||||
    &[
 | 
			
		||||
        std::any::TypeId::of::<i64>(),                      // parameter types
 | 
			
		||||
        std::any::TypeId::of::<FnPtr>(),
 | 
			
		||||
        std::any::TypeId::of::<i64>(),
 | 
			
		||||
    ],
 | 
			
		||||
    |context, args| {
 | 
			
		||||
        // 'args' is guaranteed to contain enough arguments of the correct types
 | 
			
		||||
 | 
			
		||||
        let fp = args[1].take().cast::<FnPtr>();            // 2nd argument - function pointer
 | 
			
		||||
        let value = args[2].take();                         // 3rd argument - function argument
 | 
			
		||||
 | 
			
		||||
        // The 1st argument holds the 'this' pointer.
 | 
			
		||||
        // This should be done last as it gets a mutable reference to 'args'.
 | 
			
		||||
        let this_ptr = args.get_mut(0).unwrap();
 | 
			
		||||
 | 
			
		||||
        // Use 'FnPtr::call_raw' to call the function pointer with the context
 | 
			
		||||
        // while also binding the 'this' pointer!
 | 
			
		||||
        fp.call_raw(&context, Some(this_ptr), [value])
 | 
			
		||||
    },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
let result = engine.eval::<i64>(
 | 
			
		||||
r#"
 | 
			
		||||
    fn foo(x) { this += x; }        // script-defined function 'foo'
 | 
			
		||||
 | 
			
		||||
    let x = 41;                     // object
 | 
			
		||||
    x.bar(foo, 1);                  // pass 'foo' as function pointer
 | 
			
		||||
    x
 | 
			
		||||
"#)?;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
~~~admonish tip "Tip: Hold multiple references"
 | 
			
		||||
 | 
			
		||||
In order to access a value argument that is expensive to clone _while_ holding a mutable reference
 | 
			
		||||
to the first argument, use one of the following tactics:
 | 
			
		||||
 | 
			
		||||
1. If it is a [primary type][standard types] other than [string], use `as_xxx()` as above;
 | 
			
		||||
 | 
			
		||||
2. Directly _consume_ that argument via `arg[i].take()` as above.
 | 
			
		||||
 | 
			
		||||
3. Use `split_first_mut` to partition the slice:
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
// Partition the slice
 | 
			
		||||
let (first, rest) = args.split_first_mut().unwrap();
 | 
			
		||||
 | 
			
		||||
// Mutable reference to the first parameter, of type '&mut A'
 | 
			
		||||
let this_ptr = &mut *first.write_lock::<A>().unwrap();
 | 
			
		||||
 | 
			
		||||
// Immutable reference to the second value parameter, of type '&B'
 | 
			
		||||
// This can be mutable but there is no point because the parameter is passed by value
 | 
			
		||||
let value_ref = &*rest[0].read_lock::<B>().unwrap();
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										164
									
								
								_archive/rhai_engine/rhaibook/rust/serde.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								_archive/rhai_engine/rhaibook/rust/serde.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,164 @@
 | 
			
		||||
Serialization and Deserialization of `Dynamic` with `serde`
 | 
			
		||||
===========================================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
Rhai's [`Dynamic`] type supports serialization and deserialization by
 | 
			
		||||
[`serde`](https://crates.io/crates/serde) via the [`serde`][features] feature.
 | 
			
		||||
 | 
			
		||||
```admonish tip.small
 | 
			
		||||
 | 
			
		||||
[`Dynamic`] works _both_ as a _serialization format_ as well as a data type that is serializable.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
[`serde`]: https://crates.io/crates/serde
 | 
			
		||||
[`serde_json`]: https://crates.io/crates/serde_json
 | 
			
		||||
[`serde::Serialize`]: https://docs.serde.rs/serde/trait.Serialize.html
 | 
			
		||||
[`serde::Deserialize`]: https://docs.serde.rs/serde/trait.Deserialize.html
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Serialize/Deserialize a `Dynamic`
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
With the [`serde`][features] feature turned on, [`Dynamic`] implements [`serde::Serialize`] and
 | 
			
		||||
[`serde::Deserialize`], so it can easily be serialized and deserialized with [`serde`] (for example,
 | 
			
		||||
to and from JSON via [`serde_json`]).
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
let value: Dynamic = ...;
 | 
			
		||||
 | 
			
		||||
// Serialize 'Dynamic' to JSON
 | 
			
		||||
let json = serde_json::to_string(&value);
 | 
			
		||||
 | 
			
		||||
// Deserialize 'Dynamic' from JSON
 | 
			
		||||
let result: Dynamic = serde_json::from_str(&json);
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish note.small "Custom types"
 | 
			
		||||
 | 
			
		||||
[Custom types] are serialized as text strings of the value's type name.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "BLOB's"
 | 
			
		||||
 | 
			
		||||
[BLOB's], or byte-arrays, are serialized and deserialized as simple [arrays] for some formats such as JSON.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish tip.small "Tip: Lighter alternative for JSON"
 | 
			
		||||
 | 
			
		||||
The [`serde_json`] crate is quite heavy.
 | 
			
		||||
 | 
			
		||||
If only _simple_ JSON parsing (i.e. only deserialization) of a hash object into a Rhai [object map] is required,
 | 
			
		||||
the [`Engine::parse_json`]({{rootUrl}}/language/json.md}}) method is available as a _cheap_ alternative,
 | 
			
		||||
but it does not provide the same level of correctness, nor are there any configurable options.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`Dynamic` as Serialization Format
 | 
			
		||||
---------------------------------
 | 
			
		||||
 | 
			
		||||
A [`Dynamic`] can be seamlessly converted to and from any type that implements [`serde::Serialize`]
 | 
			
		||||
and/or [`serde::Deserialize`], acting as a serialization format.
 | 
			
		||||
 | 
			
		||||
### Serialize Any Type to `Dynamic`
 | 
			
		||||
 | 
			
		||||
The function `rhai::serde::to_dynamic` automatically converts any Rust type that implements
 | 
			
		||||
[`serde::Serialize`] into a [`Dynamic`].
 | 
			
		||||
 | 
			
		||||
For primary types, this is usually not necessary because using [`Dynamic::from`][`Dynamic`] is much
 | 
			
		||||
easier and is essentially the same thing.  The only difference is treatment for integer values.
 | 
			
		||||
`Dynamic::from` keeps different integer types intact, while `rhai::serde::to_dynamic` converts them
 | 
			
		||||
all into [`INT`][standard types] (i.e. the system integer type which is `i64` or `i32` depending on
 | 
			
		||||
the [`only_i32`] feature).
 | 
			
		||||
 | 
			
		||||
Rust `struct`'s (or any type that is marked as a `serde` map) are converted into [object maps] while
 | 
			
		||||
Rust `Vec`'s (or any type that is marked as a `serde` sequence) are converted into [arrays].
 | 
			
		||||
 | 
			
		||||
While it is also simple to serialize a Rust type to `JSON` via `serde`,
 | 
			
		||||
then use [`Engine::parse_json`]({{rootUrl}}/language/json.md) to convert it into an [object map],
 | 
			
		||||
`rhai::serde::to_dynamic` serializes it to [`Dynamic`] directly via `serde` without going through the `JSON` step.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Dynamic, Map};
 | 
			
		||||
use rhai::serde::to_dynamic;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Serialize)]
 | 
			
		||||
struct Point {
 | 
			
		||||
    x: f64,
 | 
			
		||||
    y: f64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Serialize)]
 | 
			
		||||
struct MyStruct {
 | 
			
		||||
    a: i64,
 | 
			
		||||
    b: Vec<String>,
 | 
			
		||||
    c: bool,
 | 
			
		||||
    d: Point
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let x = MyStruct {
 | 
			
		||||
    a: 42,
 | 
			
		||||
    b: vec![ "hello".into(), "world".into() ],
 | 
			
		||||
    c: true,
 | 
			
		||||
    d: Point { x: 123.456, y: 999.0 }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Convert the 'MyStruct' into a 'Dynamic'
 | 
			
		||||
let map: Dynamic = to_dynamic(x);
 | 
			
		||||
 | 
			
		||||
map.is::<Map>() == true;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
### Deserialize a `Dynamic` into Any Type
 | 
			
		||||
 | 
			
		||||
The function `rhai::serde::from_dynamic` automatically converts a [`Dynamic`] value into any Rust type
 | 
			
		||||
that implements [`serde::Deserialize`].
 | 
			
		||||
 | 
			
		||||
In particular, [object maps] are converted into Rust `struct`'s (or any type that is marked as
 | 
			
		||||
a `serde` map) while [arrays] are converted into Rust `Vec`'s (or any type that is marked
 | 
			
		||||
as a `serde` sequence).
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
use rhai::{Engine, Dynamic};
 | 
			
		||||
use rhai::serde::from_dynamic;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Deserialize)]
 | 
			
		||||
struct Point {
 | 
			
		||||
    x: f64,
 | 
			
		||||
    y: f64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, serde::Deserialize)]
 | 
			
		||||
struct MyStruct {
 | 
			
		||||
    a: i64,
 | 
			
		||||
    b: Vec<String>,
 | 
			
		||||
    c: bool,
 | 
			
		||||
    d: Point
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
let engine = Engine::new();
 | 
			
		||||
 | 
			
		||||
let result: Dynamic = engine.eval(
 | 
			
		||||
r#"
 | 
			
		||||
    #{
 | 
			
		||||
        a: 42,
 | 
			
		||||
        b: [ "hello", "world" ],
 | 
			
		||||
        c: true,
 | 
			
		||||
        d: #{ x: 123.456, y: 999.0 }
 | 
			
		||||
    }
 | 
			
		||||
"#)?;
 | 
			
		||||
 | 
			
		||||
// Convert the 'Dynamic' object map into 'MyStruct'
 | 
			
		||||
let x: MyStruct = from_dynamic(&result)?;
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
```admonish warning.small "Cannot deserialize shared values"
 | 
			
		||||
 | 
			
		||||
A [`Dynamic`] containing a _shared_ value cannot be deserialized.
 | 
			
		||||
It will give a type error.
 | 
			
		||||
 | 
			
		||||
Use `Dynamic::flatten` to obtain a cloned copy before deserialization
 | 
			
		||||
(if the value is not shared, it is simply returned and not cloned).
 | 
			
		||||
 | 
			
		||||
Shared values are turned off via the [`no_closure`] feature.
 | 
			
		||||
```
 | 
			
		||||
							
								
								
									
										17
									
								
								_archive/rhai_engine/rhaibook/rust/strings-interner.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								_archive/rhai_engine/rhaibook/rust/strings-interner.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
			
		||||
Strings Interner
 | 
			
		||||
================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Because [strings] are immutable (i.e. the use the type [`ImmutableString`] instead of normal Rust `String`),
 | 
			
		||||
each operation on a [string] actually creates a new [`ImmutableString`] instance.
 | 
			
		||||
 | 
			
		||||
A _strings interner_ can substantially reduce memory usage by reusing the same [`ImmutableString`]
 | 
			
		||||
instance for the same [string] content.
 | 
			
		||||
 | 
			
		||||
An [`Engine`] contains a strings interner which is enabled by default
 | 
			
		||||
(disabled when using a [raw `Engine`]).
 | 
			
		||||
 | 
			
		||||
The maximum number of [strings] to be interned can be set via
 | 
			
		||||
[`Engine::set_max_strings_interned`][options] (set to zero to disable the strings interner).
 | 
			
		||||
							
								
								
									
										74
									
								
								_archive/rhai_engine/rhaibook/rust/strings.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								_archive/rhai_engine/rhaibook/rust/strings.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
`String` Parameters in Rust Functions
 | 
			
		||||
=====================================
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish danger "Warning: Avoid `String` parameters"
 | 
			
		||||
 | 
			
		||||
As much as possible, avoid using `String` parameters in functions.
 | 
			
		||||
 | 
			
		||||
Each `String` argument is cloned during _every_ single call to that function –
 | 
			
		||||
and the copy immediately thrown away right after the call.
 | 
			
		||||
 | 
			
		||||
Needless to say, it is _extremely_ inefficient to use `String` parameters.
 | 
			
		||||
~~~
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`&str` Maps to `ImmutableString`
 | 
			
		||||
--------------------------------
 | 
			
		||||
 | 
			
		||||
```admonish warning.side "Common mistake"
 | 
			
		||||
 | 
			
		||||
A common mistake made by novice Rhai users is to register functions with `String` parameters.
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Rust functions accepting parameters of `String` should use `&str` instead because it maps directly
 | 
			
		||||
to [`ImmutableString`] which is the type that Rhai uses to represent [strings] internally.
 | 
			
		||||
 | 
			
		||||
The parameter type `String` involves always converting an [`ImmutableString`] into a `String`
 | 
			
		||||
which mandates cloning it.
 | 
			
		||||
 | 
			
		||||
Using [`ImmutableString`] or `&str` is much more efficient.
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
fn get_len1(s: String) -> i64 {             // BAD!!! Very inefficient!!!
 | 
			
		||||
    s.len() as i64
 | 
			
		||||
}
 | 
			
		||||
fn get_len2(s: &str) -> i64 {               // this is better
 | 
			
		||||
    s.len() as i64
 | 
			
		||||
}
 | 
			
		||||
fn get_len3(s: ImmutableString) -> i64 {    // the above is equivalent to this
 | 
			
		||||
    s.len() as i64
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
engine.register_fn("len1", get_len1)
 | 
			
		||||
      .register_fn("len2", get_len2)
 | 
			
		||||
      .register_fn("len3", get_len3);
 | 
			
		||||
 | 
			
		||||
let len = engine.eval::<i64>("len1(x)")?;   // 'x' cloned, very inefficient!!!
 | 
			
		||||
let len = engine.eval::<i64>("len2(x)")?;   // 'x' is shared
 | 
			
		||||
let len = engine.eval::<i64>("len3(x)")?;   // 'x' is shared
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
~~~admonish danger "`&mut String` does not work – use `&mut ImmutableString` instead"
 | 
			
		||||
 | 
			
		||||
A function with the first parameter being `&mut String` does not match a string argument passed to it,
 | 
			
		||||
which has type `ImmutableString`.
 | 
			
		||||
 | 
			
		||||
In fact, `&mut String` is treated as an opaque [custom type].
 | 
			
		||||
 | 
			
		||||
```rust
 | 
			
		||||
fn bad(s: &mut String) { ... }              // '&mut String' will not match string values
 | 
			
		||||
 | 
			
		||||
fn good(s: &mut ImmutableString) { ... }
 | 
			
		||||
 | 
			
		||||
engine.register_fn("bad", bad)
 | 
			
		||||
      .register_fn("good", good);
 | 
			
		||||
 | 
			
		||||
engine.eval(r#"bad("hello")"#)?;            // <- error: function 'bad (string)' not found
 | 
			
		||||
 | 
			
		||||
engine.eval(r#"good("hello")"#)?;           // <- this one works
 | 
			
		||||
```
 | 
			
		||||
~~~
 | 
			
		||||
							
								
								
									
										15
									
								
								_archive/rhai_engine/rhaibook/rust/traits.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								_archive/rhai_engine/rhaibook/rust/traits.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,15 @@
 | 
			
		||||
Traits
 | 
			
		||||
======
 | 
			
		||||
 | 
			
		||||
{{#include ../links.md}}
 | 
			
		||||
 | 
			
		||||
A number of traits, under the `rhai::` module namespace, provide additional functionalities.
 | 
			
		||||
 | 
			
		||||
| Trait                    | Description                                                        | Methods                                                                                      |
 | 
			
		||||
| ------------------------ | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- |
 | 
			
		||||
| `CustomType`             | trait to build a [custom type] for use with an [`Engine`]          | `build`                                                                                      |
 | 
			
		||||
| `Func`                   | trait for creating Rust closures from script                       | `create_from_ast`, `create_from_script`                                                      |
 | 
			
		||||
| `FuncArgs`               | trait for parsing function call arguments                          | `parse`                                                                                      |
 | 
			
		||||
| `ModuleResolver`         | trait implemented by [module resolution][module resolver] services | `resolve`, `resolve_ast`, `resolve_raw`                                                      |
 | 
			
		||||
| `packages::Package`      | trait implemented by [packages]                                    | `init`, `init_engine`, `register_into_engine`, `register_into_engine_as`, `as_shared_module` |
 | 
			
		||||
| `plugin::PluginFunction` | trait implemented by [plugin] functions                            | `call`, `is_method_call`, `has_context`, `is_pure`                                           |
 | 
			
		||||
		Reference in New Issue
	
	Block a user