Add docs on serde feature.
This commit is contained in:
parent
cf2461651c
commit
b3b3a083b8
@ -21,7 +21,7 @@ num-traits = { version = "0.2.11", default-features = false }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
||||||
default = []
|
default = ["serde"]
|
||||||
plugins = []
|
plugins = []
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
@ -73,3 +73,9 @@ optional = true
|
|||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||||
instant= { version = "0.1.4", features = ["wasm-bindgen"] } # WASM implementation of std::time::Instant
|
instant= { version = "0.1.4", features = ["wasm-bindgen"] } # WASM implementation of std::time::Instant
|
||||||
|
|
||||||
|
[package.metadata.docs.rs]
|
||||||
|
features = ["serde"]
|
||||||
|
|
||||||
|
[package.metadata.playground]
|
||||||
|
features = ["serde"]
|
||||||
|
@ -4,11 +4,20 @@ Rhai Release Notes
|
|||||||
Version 0.17.0
|
Version 0.17.0
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
This version adds [`serde`](https://crates.io/crates/serde) support for working with `Dynamic` values (particularly _object maps_).
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
* `EvalAltResult::ErrorMismatchOutputType` has an extra argument containing the name of the requested type.
|
* `EvalAltResult::ErrorMismatchOutputType` has an extra argument containing the name of the requested type.
|
||||||
|
|
||||||
|
New features
|
||||||
|
------------
|
||||||
|
|
||||||
|
* New `serde` feature to allow serializating/deserializating to/from `Dynamic` values using [`serde`](https://crates.io/crates/serde).
|
||||||
|
This is particularly useful when converting a Rust `struct` to a `Dynamic` _object map_ and back.
|
||||||
|
|
||||||
|
|
||||||
Version 0.16.1
|
Version 0.16.1
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
@ -13,16 +13,21 @@ A [`Dynamic`] can be seamlessly converted to and from a type that implements `se
|
|||||||
Serialization
|
Serialization
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
While it is simple to serialize a Rust type to `JSON` via `serde`,
|
The function `rhai::ser::to_dynamic` automatically converts any Rust type that implements `serde::Serialize`
|
||||||
then use [`Engine::parse_json`]({{rootUrl}}/language/json.md) to convert it into an [object map],
|
|
||||||
Rhai supports serializing a [`Dynamic`] directly via `serde` without going through the `JSON` step.
|
|
||||||
|
|
||||||
The function `rhai::see::to_dynamic` automatically converts any Rust type that implements `serde::Serialize`
|
|
||||||
into a [`Dynamic`].
|
into a [`Dynamic`].
|
||||||
|
|
||||||
|
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
|
||||||
|
integer types intact, while `rhai::ser::to_dynamic` will convert them all into [`INT`][standard types]
|
||||||
|
(i.e. the system integer type which is `i64` or `i32` depending on the [`only_i32`] feature).
|
||||||
|
|
||||||
In particular, Rust `struct`'s (or any type that is marked as a `serde` map) are converted into [object maps]
|
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].
|
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`]({{rootUrl}}/language/json.md) to convert it into an [object map],
|
||||||
|
`rhai::ser::to_dynamic` serializes it to [`Dynamic`] directly via `serde` without going through the `JSON` step.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
use rhai::{Dynamic, Map};
|
use rhai::{Dynamic, Map};
|
||||||
use rhai::ser::to_dynamic;
|
use rhai::ser::to_dynamic;
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
//! | `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
//! | `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
||||||
//! | `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
//! | `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||||
//! | `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, `Engine`, `Scope` and [`AST`] are all `Send + Sync`. |
|
//! | `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, `Engine`, `Scope` and [`AST`] are all `Send + Sync`. |
|
||||||
//! | `serde` | Enable serialization/deserialization via [`serde`]. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
//! | `serde` | Enable serialization/deserialization via `serde`. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
||||||
//! | `internals` | Expose internal data structures (beware they may be volatile from version to version). |
|
//! | `internals` | Expose internal data structures (beware they may be volatile from version to version). |
|
||||||
//!
|
//!
|
||||||
//! See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai script engine and language.
|
//! See [The Rhai Book](https://schungx.github.io/rhai) for details on the Rhai script engine and language.
|
||||||
@ -130,10 +130,12 @@ pub mod module_resolvers {
|
|||||||
pub use crate::module::resolvers::*;
|
pub use crate::module::resolvers::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialization support for [`serde`](https://crates.io/crates/serde).
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod ser {
|
pub mod ser {
|
||||||
pub use crate::serde::ser::to_dynamic;
|
pub use crate::serde::ser::to_dynamic;
|
||||||
}
|
}
|
||||||
|
/// Deserialization support for [`serde`](https://crates.io/crates/serde).
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod de {
|
pub mod de {
|
||||||
pub use crate::serde::de::from_dynamic;
|
pub use crate::serde::de::from_dynamic;
|
||||||
|
169
src/serde/de.rs
169
src/serde/de.rs
@ -1,5 +1,8 @@
|
|||||||
|
//! Implement deserialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use super::str::ImmutableStringDeserializer;
|
use super::str::ImmutableStringDeserializer;
|
||||||
use crate::any::{Dynamic, Union};
|
use crate::any::{Dynamic, Union};
|
||||||
|
use crate::error::ParseErrorType;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
@ -22,26 +25,83 @@ use crate::stdlib::time::Instant;
|
|||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
use instant::Instant;
|
use instant::Instant;
|
||||||
|
|
||||||
|
/// Deserializer for `Dynamic` which is kept as a reference.
|
||||||
|
///
|
||||||
|
/// The reference is necessary because the deserialized type may hold references
|
||||||
|
/// (especially `&str`) to the source `Dynamic`.
|
||||||
pub struct DynamicDeserializer<'a> {
|
pub struct DynamicDeserializer<'a> {
|
||||||
value: &'a Dynamic,
|
value: &'a Dynamic,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'de> DynamicDeserializer<'de> {
|
impl<'de> DynamicDeserializer<'de> {
|
||||||
|
/// Create a `DynamicDeserializer` from a reference to a `Dynamic` value.
|
||||||
|
///
|
||||||
|
/// The reference is necessary because the deserialized type may hold references
|
||||||
|
/// (especially `&str`) to the source `Dynamic`.
|
||||||
pub fn from_dynamic(value: &'de Dynamic) -> Self {
|
pub fn from_dynamic(value: &'de Dynamic) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
pub fn type_error<R, T>(&self) -> Result<T, Box<EvalAltResult>> {
|
/// Shortcut for a type conversion error.
|
||||||
self.type_error_str(type_name::<R>())
|
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||||
}
|
|
||||||
pub fn type_error_str<T>(&self, name: &str) -> Result<T, Box<EvalAltResult>> {
|
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
name.into(),
|
type_name::<T>().into(),
|
||||||
self.value.type_name().into(),
|
self.value.type_name().into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Deserialize a `Dynamic` value into a Rust type that implements `serde::Deserialize`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_index"))]
|
||||||
|
/// # #[cfg(not(feature = "no_object"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::{Dynamic, Array, Map, INT};
|
||||||
|
/// use rhai::de::from_dynamic;
|
||||||
|
/// use serde::Deserialize;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
/// struct Hello {
|
||||||
|
/// a: INT,
|
||||||
|
/// b: bool,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, Deserialize, PartialEq)]
|
||||||
|
/// struct Test {
|
||||||
|
/// int: u32,
|
||||||
|
/// seq: Vec<String>,
|
||||||
|
/// obj: Hello,
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// let mut map = Map::new();
|
||||||
|
/// map.insert("int".into(), Dynamic::from(42_u32));
|
||||||
|
///
|
||||||
|
/// let mut map2 = Map::new();
|
||||||
|
/// map2.insert("a".into(), (123 as INT).into());
|
||||||
|
/// map2.insert("b".into(), true.into());
|
||||||
|
///
|
||||||
|
/// map.insert("obj".into(), map2.into());
|
||||||
|
///
|
||||||
|
/// let arr: Array = vec!["foo".into(), "bar".into(), "baz".into()];
|
||||||
|
/// map.insert("seq".into(), arr.into());
|
||||||
|
///
|
||||||
|
/// let value: Test = from_dynamic(&map.into())?;
|
||||||
|
///
|
||||||
|
/// let expected = Test {
|
||||||
|
/// int: 42,
|
||||||
|
/// seq: vec!["foo".into(), "bar".into(), "baz".into()],
|
||||||
|
/// obj: Hello { a: 123, b: true },
|
||||||
|
/// };
|
||||||
|
///
|
||||||
|
/// assert_eq!(value, expected);
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
||||||
value: &'de Dynamic,
|
value: &'de Dynamic,
|
||||||
) -> Result<T, Box<EvalAltResult>> {
|
) -> Result<T, Box<EvalAltResult>> {
|
||||||
@ -50,8 +110,8 @@ pub fn from_dynamic<'de, T: Deserialize<'de>>(
|
|||||||
|
|
||||||
impl Error for Box<EvalAltResult> {
|
impl Error for Box<EvalAltResult> {
|
||||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||||
Box::new(EvalAltResult::ErrorRuntime(
|
Box::new(EvalAltResult::ErrorParsing(
|
||||||
err.to_string(),
|
ParseErrorType::BadInput(err.to_string()),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -76,10 +136,10 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
Union::Array(_) => self.deserialize_seq(visitor),
|
Union::Array(_) => self.deserialize_seq(visitor),
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(_) => self.deserialize_map(visitor),
|
Union::Map(_) => self.deserialize_map(visitor),
|
||||||
Union::FnPtr(_) => unimplemented!(),
|
Union::FnPtr(_) => self.type_error(),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_std"))]
|
#[cfg(not(feature = "no_std"))]
|
||||||
Union::Variant(value) if value.is::<Instant>() => unimplemented!(),
|
Union::Variant(value) if value.is::<Instant>() => self.type_error(),
|
||||||
|
|
||||||
Union::Variant(value) if value.is::<i8>() => self.deserialize_i8(visitor),
|
Union::Variant(value) if value.is::<i8>() => self.deserialize_i8(visitor),
|
||||||
Union::Variant(value) if value.is::<i16>() => self.deserialize_i16(visitor),
|
Union::Variant(value) if value.is::<i16>() => self.deserialize_i16(visitor),
|
||||||
@ -90,64 +150,60 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
Union::Variant(value) if value.is::<u32>() => self.deserialize_u32(visitor),
|
Union::Variant(value) if value.is::<u32>() => self.deserialize_u32(visitor),
|
||||||
Union::Variant(value) if value.is::<u64>() => self.deserialize_u64(visitor),
|
Union::Variant(value) if value.is::<u64>() => self.deserialize_u64(visitor),
|
||||||
|
|
||||||
Union::Variant(_) => self.type_error_str("any"),
|
Union::Variant(_) => self.type_error(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
visitor.visit_bool(
|
visitor.visit_bool(self.value.as_bool().or_else(|_| self.type_error())?)
|
||||||
self.value
|
|
||||||
.as_bool()
|
|
||||||
.or_else(|_| self.type_error::<bool, _>())?,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i8>()
|
.downcast_ref::<i8>()
|
||||||
.map_or_else(|| self.type_error::<i8, _>(), |&x| visitor.visit_i8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i16>()
|
.downcast_ref::<i16>()
|
||||||
.map_or_else(|| self.type_error::<i16, _>(), |&x| visitor.visit_i16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i32>()
|
.downcast_ref::<i32>()
|
||||||
.map_or_else(|| self.type_error::<i32, _>(), |&x| visitor.visit_i32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<i64>()
|
.downcast_ref::<i64>()
|
||||||
.map_or_else(|| self.type_error::<i64, _>(), |&x| visitor.visit_i64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u8>()
|
.downcast_ref::<u8>()
|
||||||
.map_or_else(|| self.type_error::<u8, _>(), |&x| visitor.visit_u8(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u16>()
|
.downcast_ref::<u16>()
|
||||||
.map_or_else(|| self.type_error::<u16, _>(), |&x| visitor.visit_u16(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u32>()
|
.downcast_ref::<u32>()
|
||||||
.map_or_else(|| self.type_error::<u32, _>(), |&x| visitor.visit_u32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<u64>()
|
.downcast_ref::<u64>()
|
||||||
.map_or_else(|| self.type_error::<u64, _>(), |&x| visitor.visit_u64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
@ -155,7 +211,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
{
|
{
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<f32>()
|
.downcast_ref::<f32>()
|
||||||
.map_or_else(|| self.type_error::<f32, _>(), |&x| visitor.visit_f32(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_f32(x))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
self.type_error_str("f32")
|
self.type_error_str("f32")
|
||||||
@ -166,7 +222,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
{
|
{
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<f64>()
|
.downcast_ref::<f64>()
|
||||||
.map_or_else(|| self.type_error::<f64, _>(), |&x| visitor.visit_f64(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_f64(x))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_float")]
|
#[cfg(feature = "no_float")]
|
||||||
self.type_error_str("f64")
|
self.type_error_str("f64")
|
||||||
@ -175,12 +231,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<char>()
|
.downcast_ref::<char>()
|
||||||
.map_or_else(|| self.type_error::<char, _>(), |&x| visitor.visit_char(x))
|
.map_or_else(|| self.type_error(), |&x| visitor.visit_char(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value.downcast_ref::<ImmutableString>().map_or_else(
|
self.value.downcast_ref::<ImmutableString>().map_or_else(
|
||||||
|| self.type_error::<ImmutableString, _>(),
|
|| self.type_error(),
|
||||||
|x| visitor.visit_borrowed_str(x.as_str()),
|
|x| visitor.visit_borrowed_str(x.as_str()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -193,21 +249,21 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.value
|
self.value
|
||||||
.downcast_ref::<()>()
|
.downcast_ref::<()>()
|
||||||
.map_or_else(|| self.type_error::<(), _>(), |_| visitor.visit_unit())
|
.map_or_else(|| self.type_error(), |_| visitor.visit_unit())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_unit_struct<V: Visitor<'de>>(
|
fn deserialize_unit_struct<V: Visitor<'de>>(
|
||||||
@ -230,12 +286,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
self.value.downcast_ref::<Array>().map_or_else(
|
self.value.downcast_ref::<Array>().map_or_else(
|
||||||
|| self.type_error::<Array, _>(),
|
|| self.type_error(),
|
||||||
|arr| visitor.visit_seq(IterateArray::new(arr.iter())),
|
|arr| visitor.visit_seq(IterateArray::new(arr.iter())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
self.type_error_str("array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_tuple<V: Visitor<'de>>(
|
fn deserialize_tuple<V: Visitor<'de>>(
|
||||||
@ -259,12 +315,12 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
self.value.downcast_ref::<Map>().map_or_else(
|
self.value.downcast_ref::<Map>().map_or_else(
|
||||||
|| self.type_error::<Map, _>(),
|
|| self.type_error(),
|
||||||
|map| visitor.visit_map(IterateMap::new(map.keys(), map.values())),
|
|map| visitor.visit_map(IterateMap::new(map.keys(), map.values())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_struct<V: Visitor<'de>>(
|
fn deserialize_struct<V: Visitor<'de>>(
|
||||||
@ -282,7 +338,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
_: V,
|
_: V,
|
||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("num")
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_identifier<V: Visitor<'de>>(
|
fn deserialize_identifier<V: Visitor<'de>>(
|
||||||
@ -300,23 +356,35 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IterateArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
|
/// `SeqAccess` implementation for arrays.
|
||||||
|
struct IterateArray<'a, ITER>
|
||||||
|
where
|
||||||
|
ITER: Iterator<Item = &'a Dynamic>,
|
||||||
|
{
|
||||||
|
/// Iterator for a stream of `Dynamic` values.
|
||||||
iter: ITER,
|
iter: ITER,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateArray<'a, ITER> {
|
impl<'a, ITER> IterateArray<'a, ITER>
|
||||||
|
where
|
||||||
|
ITER: Iterator<Item = &'a Dynamic>,
|
||||||
|
{
|
||||||
pub fn new(iter: ITER) -> Self {
|
pub fn new(iter: ITER) -> Self {
|
||||||
Self { iter }
|
Self { iter }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for IterateArray<'a, ITER> {
|
impl<'a: 'de, 'de, ITER> SeqAccess<'de> for IterateArray<'a, ITER>
|
||||||
|
where
|
||||||
|
ITER: Iterator<Item = &'a Dynamic>,
|
||||||
|
{
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
fn next_element_seed<T: DeserializeSeed<'de>>(
|
fn next_element_seed<T: DeserializeSeed<'de>>(
|
||||||
&mut self,
|
&mut self,
|
||||||
seed: T,
|
seed: T,
|
||||||
) -> Result<Option<T::Value>, Box<EvalAltResult>> {
|
) -> Result<Option<T::Value>, Box<EvalAltResult>> {
|
||||||
|
// Deserialize each item coming out of the iterator.
|
||||||
match self.iter.next() {
|
match self.iter.next() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(item) => seed
|
Some(item) => seed
|
||||||
@ -326,29 +394,32 @@ impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for Iterat
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct IterateMap<
|
/// `MapAccess` implementation for maps.
|
||||||
'a,
|
struct IterateMap<'a, KEYS, VALUES>
|
||||||
|
where
|
||||||
KEYS: Iterator<Item = &'a ImmutableString>,
|
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||||
VALUES: Iterator<Item = &'a Dynamic>,
|
VALUES: Iterator<Item = &'a Dynamic>,
|
||||||
> {
|
{
|
||||||
|
// Iterator for a stream of `Dynamic` keys.
|
||||||
keys: KEYS,
|
keys: KEYS,
|
||||||
|
// Iterator for a stream of `Dynamic` values.
|
||||||
values: VALUES,
|
values: VALUES,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, KEYS: Iterator<Item = &'a ImmutableString>, VALUES: Iterator<Item = &'a Dynamic>>
|
impl<'a, KEYS, VALUES> IterateMap<'a, KEYS, VALUES>
|
||||||
IterateMap<'a, KEYS, VALUES>
|
where
|
||||||
|
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||||
|
VALUES: Iterator<Item = &'a Dynamic>,
|
||||||
{
|
{
|
||||||
pub fn new(keys: KEYS, values: VALUES) -> Self {
|
pub fn new(keys: KEYS, values: VALUES) -> Self {
|
||||||
Self { keys, values }
|
Self { keys, values }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<
|
impl<'a: 'de, 'de, KEYS, VALUES> MapAccess<'de> for IterateMap<'a, KEYS, VALUES>
|
||||||
'a: 'de,
|
where
|
||||||
'de,
|
|
||||||
KEYS: Iterator<Item = &'a ImmutableString>,
|
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||||
VALUES: Iterator<Item = &'a Dynamic>,
|
VALUES: Iterator<Item = &'a Dynamic>,
|
||||||
> MapAccess<'de> for IterateMap<'a, KEYS, VALUES>
|
|
||||||
{
|
{
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
@ -356,6 +427,7 @@ impl<
|
|||||||
&mut self,
|
&mut self,
|
||||||
seed: K,
|
seed: K,
|
||||||
) -> Result<Option<K::Value>, Box<EvalAltResult>> {
|
) -> Result<Option<K::Value>, Box<EvalAltResult>> {
|
||||||
|
// Deserialize each `ImmutableString` key coming out of the keys iterator.
|
||||||
match self.keys.next() {
|
match self.keys.next() {
|
||||||
None => Ok(None),
|
None => Ok(None),
|
||||||
Some(item) => seed
|
Some(item) => seed
|
||||||
@ -368,6 +440,7 @@ impl<
|
|||||||
&mut self,
|
&mut self,
|
||||||
seed: V,
|
seed: V,
|
||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
// Deserialize each value item coming out of the iterator.
|
||||||
seed.deserialize(&mut DynamicDeserializer::from_dynamic(
|
seed.deserialize(&mut DynamicDeserializer::from_dynamic(
|
||||||
self.values.next().unwrap(),
|
self.values.next().unwrap(),
|
||||||
))
|
))
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Helper module defining serialization/deserialization support for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
pub mod de;
|
pub mod de;
|
||||||
pub mod ser;
|
pub mod ser;
|
||||||
mod str;
|
mod str;
|
||||||
|
180
src/serde/ser.rs
180
src/serde/ser.rs
@ -1,3 +1,5 @@
|
|||||||
|
//! Implement serialization support of `Dynamic` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use crate::any::Dynamic;
|
use crate::any::Dynamic;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -15,30 +17,72 @@ use serde::Serialize;
|
|||||||
|
|
||||||
use crate::stdlib::{any::type_name, fmt, mem};
|
use crate::stdlib::{any::type_name, fmt, mem};
|
||||||
|
|
||||||
|
/// Serializer for `Dynamic` which is kept as a reference.
|
||||||
pub struct DynamicSerializer {
|
pub struct DynamicSerializer {
|
||||||
|
/// Buffer to hold a temporary key.
|
||||||
key: Dynamic,
|
key: Dynamic,
|
||||||
|
/// Buffer to hold a temporary value.
|
||||||
value: Dynamic,
|
value: Dynamic,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DynamicSerializer {
|
impl DynamicSerializer {
|
||||||
|
/// Create a `DynamicSerializer` from a `Dynamic` value.
|
||||||
pub fn new(value: Dynamic) -> Self {
|
pub fn new(value: Dynamic) -> Self {
|
||||||
Self {
|
Self {
|
||||||
key: Default::default(),
|
key: Default::default(),
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn type_error<R, T>(&self) -> Result<T, Box<EvalAltResult>> {
|
|
||||||
self.type_error_str(type_name::<R>())
|
|
||||||
}
|
|
||||||
pub fn type_error_str<T>(&self, name: &str) -> Result<T, Box<EvalAltResult>> {
|
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
name.into(),
|
|
||||||
self.value.type_name().into(),
|
|
||||||
Position::none(),
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Serialize a Rust type that implements `serde::Serialize` into a `Dynamic`.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||||
|
/// # #[cfg(not(feature = "no_index"))]
|
||||||
|
/// # #[cfg(not(feature = "no_object"))]
|
||||||
|
/// # #[cfg(not(feature = "no_float"))]
|
||||||
|
/// # {
|
||||||
|
/// use rhai::{Dynamic, Array, Map, INT};
|
||||||
|
/// use rhai::ser::to_dynamic;
|
||||||
|
/// use serde::Serialize;
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, serde::Serialize, PartialEq)]
|
||||||
|
/// struct Point {
|
||||||
|
/// x: f64,
|
||||||
|
/// y: f64
|
||||||
|
/// }
|
||||||
|
///
|
||||||
|
/// #[derive(Debug, serde::Serialize, PartialEq)]
|
||||||
|
/// 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 value = to_dynamic(x)?;
|
||||||
|
///
|
||||||
|
/// assert!(value.is::<Map>());
|
||||||
|
///
|
||||||
|
/// let map = value.cast::<Map>();
|
||||||
|
/// let point = map.get("d").unwrap().downcast_ref::<Map>().unwrap();
|
||||||
|
/// assert_eq!(*point.get("x").unwrap().downcast_ref::<f64>().unwrap(), 123.456);
|
||||||
|
/// assert_eq!(*point.get("y").unwrap().downcast_ref::<f64>().unwrap(), 999.0);
|
||||||
|
/// # }
|
||||||
|
/// # Ok(())
|
||||||
|
/// # }
|
||||||
|
/// ```
|
||||||
pub fn to_dynamic<T: Serialize>(value: T) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn to_dynamic<T: Serialize>(value: T) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let mut s = DynamicSerializer::new(Default::default());
|
let mut s = DynamicSerializer::new(Default::default());
|
||||||
value.serialize(&mut s)
|
value.serialize(&mut s)
|
||||||
@ -141,17 +185,11 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
Ok(Dynamic::from(v))
|
||||||
return Ok(Dynamic::from(v));
|
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
return self.type_error_str("f32");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_float"))]
|
Ok(Dynamic::from(v))
|
||||||
return Ok(v.into());
|
|
||||||
#[cfg(feature = "no_float")]
|
|
||||||
return self.type_error_str("f64");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_char(self, v: char) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_char(self, v: char) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
@ -162,8 +200,8 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
Ok(v.to_string().into())
|
Ok(v.to_string().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_bytes(self, _: &[u8]) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
Ok(Dynamic::from(v.to_vec()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_none(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn serialize_none(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
@ -216,7 +254,11 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(DynamicSerializer::new(Array::new().into()));
|
return Ok(DynamicSerializer::new(Array::new().into()));
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return self.type_error_str("array");
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"Dynamic".into(),
|
||||||
|
"array".into(),
|
||||||
|
Position::none(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Box<EvalAltResult>> {
|
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Box<EvalAltResult>> {
|
||||||
@ -245,7 +287,11 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(DynamicSerializer::new(Map::new().into()));
|
return Ok(DynamicSerializer::new(Map::new().into()));
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return self.type_error_str("map");
|
return Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"Dynamic".into(),
|
||||||
|
"map".into(),
|
||||||
|
Position::none(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_struct(
|
fn serialize_struct(
|
||||||
@ -278,15 +324,12 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(arr) = self.value.downcast_mut::<Array>() {
|
let arr = self.value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Array, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
self.type_error_str("array")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the sequence.
|
// Close the sequence.
|
||||||
@ -294,7 +337,7 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return self.type_error_str("array");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,22 +352,19 @@ impl SerializeTuple for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(arr) = self.value.downcast_mut::<Array>() {
|
let arr = self.value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Array, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
self.type_error_str("array")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return self.type_error_str("array");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,22 +379,19 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(arr) = self.value.downcast_mut::<Array>() {
|
let arr = self.value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Array, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
self.type_error_str("array")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return self.type_error_str("array");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,22 +406,19 @@ impl SerializeTupleVariant for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(arr) = self.value.downcast_mut::<Array>() {
|
let arr = self.value.downcast_mut::<Array>().unwrap();
|
||||||
arr.push(value);
|
arr.push(value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Array, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
self.type_error_str("array")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return self.type_error_str("array");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +433,7 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_value<T: ?Sized + Serialize>(
|
fn serialize_value<T: ?Sized + Serialize>(
|
||||||
@ -410,17 +444,20 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
{
|
{
|
||||||
let key = mem::take(&mut self.key)
|
let key = mem::take(&mut self.key)
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.or_else(|_| self.type_error::<String, _>())?;
|
.map_err(|typ| {
|
||||||
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
"string".into(),
|
||||||
|
typ.into(),
|
||||||
|
Position::none(),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(map) = self.value.downcast_mut::<Map>() {
|
let map = self.value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key, value);
|
map.insert(key, value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Map, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
||||||
@ -431,26 +468,27 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let key: Dynamic = key.serialize(&mut *self)?;
|
let key: Dynamic = key.serialize(&mut *self)?;
|
||||||
let key = key
|
let key = key.take_immutable_string().map_err(|typ| {
|
||||||
.take_immutable_string()
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
.or_else(|_| self.type_error::<String, _>())?;
|
"string".into(),
|
||||||
|
typ.into(),
|
||||||
|
Position::none(),
|
||||||
|
))
|
||||||
|
})?;
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(map) = self.value.downcast_mut::<Map>() {
|
let map = self.value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key, value);
|
map.insert(key, value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Map, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return self.type_error_str("map");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,22 +504,19 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(map) = self.value.downcast_mut::<Map>() {
|
let map = self.value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key.into(), value);
|
map.insert(key.into(), value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Map, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return self.type_error_str("map");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -497,21 +532,18 @@ impl SerializeStructVariant for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
{
|
{
|
||||||
let value = value.serialize(&mut *self)?;
|
let value = value.serialize(&mut *self)?;
|
||||||
if let Some(map) = self.value.downcast_mut::<Map>() {
|
let map = self.value.downcast_mut::<Map>().unwrap();
|
||||||
map.insert(key.into(), value);
|
map.insert(key.into(), value);
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
|
||||||
self.type_error::<Map, _>()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
self.type_error_str("map")
|
unreachable!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self.value);
|
return Ok(self.value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return self.type_error_str("map");
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
//! Implement deserialization support of `ImmutableString` for [`serde`](https://crates.io/crates/serde).
|
||||||
|
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
@ -6,20 +8,20 @@ use serde::de::{Deserializer, Visitor};
|
|||||||
|
|
||||||
use crate::stdlib::any::type_name;
|
use crate::stdlib::any::type_name;
|
||||||
|
|
||||||
|
/// Deserializer for `ImmutableString`.
|
||||||
pub struct ImmutableStringDeserializer<'a> {
|
pub struct ImmutableStringDeserializer<'a> {
|
||||||
value: &'a ImmutableString,
|
value: &'a ImmutableString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ImmutableStringDeserializer<'a> {
|
impl<'a> ImmutableStringDeserializer<'a> {
|
||||||
|
/// Create an `ImmutableStringDeserializer` from an `ImmutableString` reference.
|
||||||
pub fn from_str(value: &'a ImmutableString) -> Self {
|
pub fn from_str(value: &'a ImmutableString) -> Self {
|
||||||
Self { value }
|
Self { value }
|
||||||
}
|
}
|
||||||
pub fn type_error<R, T>(&self) -> Result<T, Box<EvalAltResult>> {
|
/// Shortcut for a type conversion error.
|
||||||
self.type_error_str(type_name::<R>())
|
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||||
}
|
|
||||||
pub fn type_error_str<T>(&self, name: &str) -> Result<T, Box<EvalAltResult>> {
|
|
||||||
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
Err(Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
name.into(),
|
type_name::<T>().into(),
|
||||||
"string".into(),
|
"string".into(),
|
||||||
Position::none(),
|
Position::none(),
|
||||||
)))
|
)))
|
||||||
@ -33,42 +35,43 @@ impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
|||||||
self.deserialize_str(v)
|
self.deserialize_str(v)
|
||||||
}
|
}
|
||||||
fn deserialize_bool<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_bool<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<bool, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_i8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<i8, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_i16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<i16, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_i32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<i32, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_i64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_i64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<i64, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_u8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<u8, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_u16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<u16, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_u32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<u32, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_u64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_u64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<u64, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_f32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("f32")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_f64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_f64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("f64")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_char<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_char<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<char, _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_str<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_str<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
|
// Only allow deserialization into a string.
|
||||||
v.visit_borrowed_str(self.value.as_str())
|
v.visit_borrowed_str(self.value.as_str())
|
||||||
}
|
}
|
||||||
fn deserialize_string<V: Visitor<'de>>(
|
fn deserialize_string<V: Visitor<'de>>(
|
||||||
@ -78,16 +81,16 @@ impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
|||||||
self.deserialize_str(visitor)
|
self.deserialize_str(visitor)
|
||||||
}
|
}
|
||||||
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("bytes array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("option")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_unit<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_unit<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error::<(), _>()
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_unit_struct<V: Visitor<'de>>(
|
fn deserialize_unit_struct<V: Visitor<'de>>(
|
||||||
self,
|
self,
|
||||||
@ -104,7 +107,7 @@ impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
|||||||
v.visit_newtype_struct(self)
|
v.visit_newtype_struct(self)
|
||||||
}
|
}
|
||||||
fn deserialize_seq<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_seq<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("array")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_tuple<V: Visitor<'de>>(
|
fn deserialize_tuple<V: Visitor<'de>>(
|
||||||
self,
|
self,
|
||||||
@ -122,7 +125,7 @@ impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
|||||||
self.deserialize_seq(v)
|
self.deserialize_seq(v)
|
||||||
}
|
}
|
||||||
fn deserialize_map<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_map<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("map")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_struct<V: Visitor<'de>>(
|
fn deserialize_struct<V: Visitor<'de>>(
|
||||||
self,
|
self,
|
||||||
@ -138,7 +141,7 @@ impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
|||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
_: V,
|
_: V,
|
||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.type_error_str("enum")
|
self.type_error()
|
||||||
}
|
}
|
||||||
fn deserialize_identifier<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
fn deserialize_identifier<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||||
self.deserialize_str(v)
|
self.deserialize_str(v)
|
||||||
|
Loading…
Reference in New Issue
Block a user