Interop Dynamic
Data with Rust
Create a Dynamic
from Rust Type
Rust typeT: Clone ,K: Into<String> | Unavailable under | Use API |
---|---|---|
INT (i64 or i32 ) | value.into() | |
FLOAT (f64 or f32 ) | no_float | value.into() |
Decimal (requires decimal ) | value.into() | |
bool | value.into() | |
() | value.into() | |
String , &str , ImmutableString | value.into() | |
char | value.into() | |
Array | no_index | Dynamic::from_array(value) |
Blob | no_index | Dynamic::from_blob(value) |
Vec<T> , &[T] , Iterator<T> | no_index | value.into() |
Map | no_object | Dynamic::from_map(value) |
HashMap<K, T> , HashSet<K> ,BTreeMap<K, T> , BTreeSet<K> | no_object | value.into() |
INT..INT , INT..=INT | value.into() | |
Rc<RwLock<T>> or Arc<Mutex<T>> | no_closure | value.into() |
Instant | 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
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 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 | 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 ? |
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> |
as_bool | Result<bool, &str> | |
as_char | Result<char, &str> | |
into_string | Result<String, &str> | |
into_immutable_string | Result<ImmutableString, &str> | |
into_array | no_index | Result<Array, &str> |
into_blob | no_index | Result<Blob, &str> |
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 |
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 |