rhai/doc/src/rust/serde.md

127 lines
3.9 KiB
Markdown
Raw Normal View History

2020-07-03 11:19:55 +02:00
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.
2020-08-23 08:50:53 +02:00
A [`Dynamic`] can be seamlessly converted to and from a type that implements
[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) and/or
[`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html).
2020-07-03 11:19:55 +02:00
Serialization
-------------
2020-10-10 07:43:14 +02:00
The function `rhai::serde::to_dynamic` automatically converts any Rust type that implements
2020-08-23 08:50:53 +02:00
[`serde::Serialize`](https://docs.serde.rs/serde/trait.Serialize.html) into a [`Dynamic`].
2020-07-03 16:42:56 +02:00
2020-07-04 09:39:40 +02:00
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` will keep the different
2020-10-10 07:43:14 +02:00
integer types intact, while `rhai::serde::to_dynamic` will convert them all into [`INT`][standard types]
2020-07-04 09:39:40 +02:00
(i.e. the system integer type which is `i64` or `i32` depending on the [`only_i32`] feature).
2020-07-03 16:42:56 +02:00
In particular, 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].
2020-07-04 09:39:40 +02:00
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],
2020-10-10 07:43:14 +02:00
`rhai::serde::to_dynamic` serializes it to [`Dynamic`] directly via `serde` without going through the `JSON` step.
2020-07-04 09:39:40 +02:00
2020-07-03 16:42:56 +02:00
```rust
use rhai::{Dynamic, Map};
2020-10-10 07:43:14 +02:00
use rhai::serde::to_dynamic;
2020-07-03 16:42:56 +02:00
#[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;
```
2020-07-03 11:19:55 +02:00
Deserialization
---------------
2020-10-10 07:43:14 +02:00
The function `rhai::serde::from_dynamic` automatically converts a [`Dynamic`] value into any Rust type
2020-08-23 08:50:53 +02:00
that implements [`serde::Deserialize`](https://docs.serde.rs/serde/trait.Deserialize.html).
2020-07-03 11:19:55 +02:00
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};
2020-10-10 07:43:14 +02:00
use rhai::serde::from_dynamic;
2020-07-03 11:19:55 +02:00
#[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#"
2020-08-07 12:40:31 +02:00
##{
2020-07-03 11:19:55 +02:00
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)?;
```
2020-08-23 08:50:53 +02:00
2020-09-28 16:14:19 +02:00
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.
2020-08-23 08:50:53 +02:00
Lighter Alternative
-------------------
The [`serde`](https://crates.io/crates/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`]({{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.