This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/rhai_engine/rhaibook/language/dynamic-rust.md
2025-04-19 08:10:30 +02:00

19 KiB

Interop Dynamic Data with Rust

{{#include ../links.md}}

Create a Dynamic from Rust Type

Rust type
T: Clone,
K: Into<String>
Unavailable under Use API
INT (i64 or i32) value.into()
FLOAT (f64 or f32) [no_float] value.into()
[Decimal][rust_decimal] (requires [decimal]) value.into()
bool value.into()
[()] value.into()
[String][string], [&str][string], [ImmutableString] value.into()
char value.into()
[Array][array] [no_index] Dynamic::from_array(value)
[Blob][BLOB] [no_index] Dynamic::from_blob(value)
Vec<T>, &[T], Iterator<T> [no_index] value.into()
[Map][object map] [no_object] Dynamic::from_map(value)
HashMap<K, T>, HashSet<K>,
BTreeMap<K, T>, BTreeSet<K>
[no_object] value.into()
[INT..INT][range], [INT..=INT][range] value.into()
Rc<RwLock<T>> or Arc<Mutex<T>> [no_closure] value.into()
[Instant][timestamp] [no_time] or [no_std] value.into()
All types (including above) Dynamic::from(value)

Type Checking and Casting


The `try_cast` method does not panic but returns `None` upon failure.

The `try_cast_result` method also does not panic but returns the original value upon failure.

A [Dynamic] value's actual type can be checked via Dynamic::is.

The cast method then converts the value into a specific, known type.

Use clone_cast to clone a reference to [Dynamic].

let list: Array = engine.eval("...")?;      // return type is 'Array'
let item = list[0].clone();                 // an element in an 'Array' is 'Dynamic'

item.is::<i64>() == true;                   // 'is' returns whether a 'Dynamic' value is of a particular type

let value = item.cast::<i64>();             // if the element is 'i64', this succeeds; otherwise it panics
let value: i64 = item.cast();               // type can also be inferred

let value = item.try_cast::<i64>()?;        // 'try_cast' does not panic when the cast fails, but returns 'None'

let value = list[0].clone_cast::<i64>();    // use 'clone_cast' on '&Dynamic'
let value: i64 = list[0].clone_cast();

Type Name and Matching Types

The type_name method gets the name of the actual type as a static string slice, which can be match-ed against.

This is a very simple and direct way to act on a [Dynamic] value based on the actual type of the data value.

let list: Array = engine.eval("...")?;      // return type is 'Array'
let item = list[0];                         // an element in an 'Array' is 'Dynamic'

match item.type_name() {                    // 'type_name' returns the name of the actual Rust type
    "()" => ...
    "i64" => ...
    "f64" => ...
    "rust_decimal::Decimal" => ...
    "core::ops::range::Range<i64>" => ...
    "core::ops::range::RangeInclusive<i64>" => ...
    "alloc::string::String" => ...
    "bool" => ...
    "char" => ...
    "rhai::FnPtr" => ...
    "std::time::Instant" => ...
    "crate::path::to::module::TestStruct" => ...
        :
}

`type_name` always returns the _full_ Rust path name of the type, even when the type
has been registered with a friendly name via `Engine::register_type_with_name`.

This behavior is different from that of the [`type_of`][`type_of()`] function in Rhai.

Getting a Reference to Data

Use Dynamic::read_lock and Dynamic::write_lock to get an immutable/mutable reference to the data inside a [Dynamic].

struct TheGreatQuestion {
    answer: i64
}

let question = TheGreatQuestion { answer: 42 };

let mut value: Dynamic = Dynamic::from(question);

let q_ref: &TheGreatQuestion =
        &*value.read_lock::<TheGreatQuestion>().unwrap();
//                       ^^^^^^^^^^^^^^^^^^^^ cast to data type

println!("answer = {}", q_ref.answer);          // prints 42

let q_mut: &mut TheGreatQuestion =
        &mut *value.write_lock::<TheGreatQuestion>().unwrap();
//                            ^^^^^^^^^^^^^^^^^^^^ cast to data type

q_mut.answer = 0;                               // mutate value

let value = value.cast::<TheGreatQuestion>();

println!("new answer = {}", value.answer);      // prints 0

As the naming shows, something is _locked_ in order to allow accessing the data within a [`Dynamic`],
and that something is a _shared value_ created by capturing variables from [closures].

Shared values are implemented as `Rc<RefCell<Dynamic>>` (`Arc<RwLock<Dynamic>>` under [`sync`]).

If the value is _not_ a shared value, or if running under [`no_closure`] where there is
no capturing, this API de-sugars to a simple reference cast.

In other words, there is no locking and reference counting overhead for the vast majority of
non-shared values.

If the value _is_ a shared value, then it is first _locked_ and the returned _lock guard_
allows access to the underlying value in the specified type.

Methods and Traits

The following methods are available when working with [Dynamic]:

Method Not available under Return type Description
type_name &str name of the value's type
into_shared [no_closure] [Dynamic] turn the value into a shared value
flatten_clone [Dynamic] clone the value (a shared value, if any, is cloned into a separate copy)
flatten [Dynamic] clone the value into a separate copy if it is shared and there are multiple outstanding references, otherwise shared values are turned unshared
read_lock<T> [no_closure] (pass thru') Option< guard to T> lock the value for reading
write_lock<T> [no_closure] (pass thru') Option< guard to T> lock the value exclusively for writing
deep_scan recursively scan for [Dynamic] values (e.g. items inside an [array] or [object map], or [curried arguments][currying] in a [function pointer])

Constructor instance methods

Method Not available under Value type Data type
from_bool bool bool
from_int INT integer number
from_float [no_float] FLOAT floating-point number
from_decimal non-[decimal] [Decimal][rust_decimal] [Decimal][rust_decimal]
from_str &str [string]
from_char char [character]
from_array [no_index] Vec<T> [array]
from_blob [no_index] Vec<u8> [BLOB]
from_map [no_object] Map [object map]
from_timestamp [no_time] or [no_std] std::time::Instant ([instant::Instant] if [WASM] build) [timestamp]
from<T> T [custom type]

Detection methods

Method Not available under Return type Description
is<T> bool is the value of type T?
is_variant bool is the value a trait object (i.e. not one of Rhai's [standard types])?
is_read_only bool is the value [constant]? A [constant] value should not be modified.
is_shared [no_closure] bool is the value shared via a [closure]?
is_locked [no_closure] bool is the value shared and locked (i.e. currently being read)?
is_unit bool is the value [()]?
is_int bool is the value an integer?
is_float [no_float] bool is the value a floating-point number?
is_decimal non-[decimal] bool is the value a [Decimal][rust_decimal]?
is_bool bool is the value a bool?
is_char bool is the value a [character]?
is_string bool is the value a [string]?
is_array [no_index] bool is the value an [array]?
is_blob [no_index] bool is the value a [BLOB]?
is_map [no_object] bool is the value an [object map]?
is_timestamp [no_time] or [no_std] bool is the value a [timestamp]?

Casting methods

The following methods cast a [Dynamic] into a specific type:

Method Not available under Return type (error is name of actual type if &str)
cast<T> T (panics on failure)
try_cast<T> Option<T>
try_cast_result<T> Result<T, Dynamic>
clone_cast<T> cloned copy of T (panics on failure)
as_unit Result<(), &str>
as_int Result<INT, &str>
as_float [no_float] Result<FLOAT, &str>
as_decimal non-[decimal] [Result<Decimal, &str>][rust_decimal]
as_bool Result<bool, &str>
as_char Result<char, &str>
as_immutable_string_ref [Result<impl Deref<Target=ImmutableString>, &str>][ImmutableString]
as_immutable_string_mut [Result<impl DerefMut<Target=ImmutableString>, &str>][ImmutableString]
as_array_ref [no_index] [Result<impl Deref<Target=Array>, &str>][array]
as_array_mut [no_index] [Result<impl DerefMut<Target=Array>, &str>][array]
as_blob_ref [no_index] [Result<impl Deref<Target=Blob>, &str>][BLOB]
as_blob_mut [no_index] [Result<impl DerefMut<Target=Blob>, &str>][BLOB]
as_map_ref [no_object] [Result<impl Deref<Target=Map>, &str>][object map]
as_map_mut [no_object] [Result<impl DerefMut<Target=Map>, &str>][object map]
into_string Result<String, &str>
into_immutable_string [Result<ImmutableString, &str>][ImmutableString]
into_array [no_index] [Result<Array, &str>][array]
into_blob [no_index] [Result<Blob, &str>][BLOB]
into_typed_array<T> [no_index] Result<Vec<T>, &str>

Constructor traits

The following constructor traits are implemented for [Dynamic] where T: Clone:

Trait Not available under Data type
From<()> ()
From<INT> integer number
From<FLOAT> [no_float] floating-point number
From<Decimal> non-[decimal] [Decimal][rust_decimal]
From<bool> bool
From<S: Into<ImmutableString>>
e.g. From<String>, From<&str>
[ImmutableString]
From<char> [character]
From<Vec<T>> [no_index] [array]
From<&[T]> [no_index] [array]
From<BTreeMap<K: Into<SmartString>, T>>
e.g. From<BTreeMap<String, T>>
[no_object] [object map]
From<BTreeSet<K: Into<SmartString>>>
e.g. From<BTreeSet<String>>
[no_object] [object map]
From<HashMap<K: Into<SmartString>, T>>
e.g. From<HashMap<String, T>>
[no_object] or [no_std] [object map]
From<HashSet<K: Into<SmartString>>>
e.g. From<HashSet<String>>
[no_object] or [no_std] [object map]
From<FnPtr> [function pointer]
From<Instant> [no_time] or [no_std] [timestamp]
From<Rc<RefCell<Dynamic>>> [sync] or [no_closure] [Dynamic]
From<Arc<RwLock<Dynamic>>> ([sync]) non-[sync] or [no_closure] [Dynamic]
FromIterator<X: IntoIterator<Item=T>> [no_index] [array]