Serialization and Deserialization of Dynamic
with serde
Rhai’s Dynamic
type supports serialization and deserialization by
serde
via the serde
feature.
Dynamic
works both as a serialization format as well as a data type that is serializable.
Serialize/Deserialize a Dynamic
With the serde
feature turned on, Dynamic
implements
serde::Serialize
and
serde::Deserialize
, so it can easily
be serialized and deserialized with serde
.
#![allow(unused)] fn main() { 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); }
Custom types are serialized as text strings of the value’s type name.
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
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
(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
to convert it into an object map,
rhai::serde::to_dynamic
serializes it to Dynamic
directly via serde
without going through the JSON
step.
#![allow(unused)] fn main() { 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).
#![allow(unused)] fn main() { 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)?; }
Cannot Deserialize Shared Values
A Dynamic
containing a shared value cannot be deserialized – i.e. 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.
Lighter Alternative
The serde
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
method is available as a cheap alternative,
but it does not provide the same level of correctness, nor are there any configurable options.