FlowLang is built on the Rhai embedded scripting language. The language semantics on these pages are Rhai's; FlowLang adds the typed Connect- block surface on top (see the namespace catalogue).

Interop Dynamic Data with Rust

Create a Dynamic from Rust Type

Rust type
T: Clone,
K: Into<String>
Unavailable underUse API
INT (i64 or i32)value.into()
FLOAT (f64 or f32)no_floatvalue.into()
Decimal (requires decimal)value.into()
boolvalue.into()
()value.into()
String, &str, ImmutableStringvalue.into()
charvalue.into()
Arrayno_indexDynamic::from_array(value)
Blobno_indexDynamic::from_blob(value)
Vec<T>, &[T], Iterator<T>no_indexvalue.into()
Mapno_objectDynamic::from_map(value)
HashMap<K, T>, HashSet<K>,
BTreeMap<K, T>, BTreeSet<K>
no_objectvalue.into()
INT..INT, INT..=INTvalue.into()
Rc<RwLock<T>> or Arc<Mutex<T>>no_closurevalue.into()
Instantno_time or no_stdvalue.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:

MethodNot available underReturn typeDescription
type_name&strname of the value's type
into_sharedno_closureDynamicturn the value into a shared value
flatten_cloneDynamicclone the value (a shared value, if any, is cloned into a separate copy)
flattenDynamicclone 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_scanrecursively scan for Dynamic values (e.g. items inside an array or object map, or curried arguments in a function pointer)

Constructor instance methods

MethodNot available underValue typeData type
from_boolboolbool
from_intINTinteger number
from_floatno_floatFLOATfloating-point number
from_decimalnon-decimalDecimalDecimal
from_str&strstring
from_charcharcharacter
from_arrayno_indexVec<T>array
from_blobno_indexVec<u8>BLOB
from_mapno_objectMapobject map
from_timestampno_time or no_stdstd::time::Instant (instant::Instant if WASM build)timestamp
from<T>Tcustom type

Detection methods

MethodNot available underReturn typeDescription
is<T>boolis the value of type T?
is_variantboolis the value a trait object (i.e. not one of Rhai's standard types)?
is_read_onlyboolis the value constant? A constant value should not be modified.
is_sharedno_closureboolis the value shared via a closure?
is_lockedno_closureboolis the value shared and locked (i.e. currently being read)?
is_unitboolis the value ()?
is_intboolis the value an integer?
is_floatno_floatboolis the value a floating-point number?
is_decimalnon-decimalboolis the value a Decimal?
is_boolboolis the value a bool?
is_charboolis the value a character?
is_stringboolis the value a string?
is_arrayno_indexboolis the value an array?
is_blobno_indexboolis the value a BLOB?
is_mapno_objectboolis the value an object map?
is_timestampno_time or no_stdboolis the value a timestamp?

Casting methods

The following methods cast a Dynamic into a specific type:

MethodNot available underReturn 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_unitResult<(), &str>
as_intResult<INT, &str>
as_floatno_floatResult<FLOAT, &str>
as_decimalnon-decimalResult<Decimal, &str>
as_boolResult<bool, &str>
as_charResult<char, &str>
as_immutable_string_refResult<impl Deref<Target=ImmutableString>, &str>
as_immutable_string_mutResult<impl DerefMut<Target=ImmutableString>, &str>
as_array_refno_indexResult<impl Deref<Target=Array>, &str>
as_array_mutno_indexResult<impl DerefMut<Target=Array>, &str>
as_blob_refno_indexResult<impl Deref<Target=Blob>, &str>
as_blob_mutno_indexResult<impl DerefMut<Target=Blob>, &str>
as_map_refno_objectResult<impl Deref<Target=Map>, &str>
as_map_mutno_objectResult<impl DerefMut<Target=Map>, &str>
into_stringResult<String, &str>
into_immutable_stringResult<ImmutableString, &str>
into_arrayno_indexResult<Array, &str>
into_blobno_indexResult<Blob, &str>
into_typed_array<T>no_indexResult<Vec<T>, &str>

Constructor traits

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

TraitNot available underData type
From<()>()
From<INT>integer number
From<FLOAT>no_floatfloating-point number
From<Decimal>non-decimalDecimal
From<bool>bool
From<S: Into<ImmutableString>>
e.g. From<String>, From<&str>
ImmutableString
From<char>character
From<Vec<T>>no_indexarray
From<&[T]>no_indexarray
From<BTreeMap<K: Into<SmartString>, T>>
e.g. From<BTreeMap<String, T>>
no_objectobject map
From<BTreeSet<K: Into<SmartString>>>
e.g. From<BTreeSet<String>>
no_objectobject map
From<HashMap<K: Into<SmartString>, T>>
e.g. From<HashMap<String, T>>
no_object or no_stdobject map
From<HashSet<K: Into<SmartString>>>
e.g. From<HashSet<String>>
no_object or no_stdobject map
From<FnPtr>function pointer
From<Instant>no_time or no_stdtimestamp
From<Rc<RefCell<Dynamic>>>sync or no_closureDynamic
From<Arc<RwLock<Dynamic>>> (sync)non-sync or no_closureDynamic
FromIterator<X: IntoIterator<Item=T>>no_indexarray