Rename serde_impl to serde.
This commit is contained in:
616
src/serde/de.rs
Normal file
616
src/serde/de.rs
Normal file
@@ -0,0 +1,616 @@
|
||||
//! Implement deserialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
||||
|
||||
use super::str::ImmutableStringDeserializer;
|
||||
use crate::dynamic::Union;
|
||||
use crate::stdlib::{any::type_name, boxed::Box, fmt, string::ToString};
|
||||
use crate::{Dynamic, EvalAltResult, ImmutableString, LexError, Position};
|
||||
use serde::de::{DeserializeSeed, Error, IntoDeserializer, MapAccess, SeqAccess, Visitor};
|
||||
use serde::{Deserialize, Deserializer};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Deserializer for [`Dynamic`][crate::Dynamic] which is kept as a reference.
|
||||
///
|
||||
/// The reference is necessary because the deserialized type may hold references
|
||||
/// (especially `&str`) to the source [`Dynamic`][crate::Dynamic].
|
||||
struct DynamicDeserializer<'a> {
|
||||
value: &'a Dynamic,
|
||||
}
|
||||
|
||||
impl<'de> DynamicDeserializer<'de> {
|
||||
/// Create a [`DynamicDeserializer`] from a reference to a [`Dynamic`][crate::Dynamic] value.
|
||||
///
|
||||
/// The reference is necessary because the deserialized type may hold references
|
||||
/// (especially `&str`) to the source [`Dynamic`][crate::Dynamic].
|
||||
pub fn from_dynamic(value: &'de Dynamic) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||
self.type_error_str(type_name::<T>())
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
fn type_error_str<T>(&self, error: &str) -> Result<T, Box<EvalAltResult>> {
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
error.into(),
|
||||
self.value.type_name().into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
fn deserialize_int<V: Visitor<'de>>(
|
||||
&mut self,
|
||||
v: crate::INT,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return visitor.visit_i64(v);
|
||||
#[cfg(feature = "only_i32")]
|
||||
return visitor.visit_i32(v);
|
||||
}
|
||||
}
|
||||
|
||||
/// Deserialize a [`Dynamic`][crate::Dynamic] value into a Rust type that implements [`serde::Deserialize`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// # #[cfg(not(feature = "no_index"))]
|
||||
/// # #[cfg(not(feature = "no_object"))]
|
||||
/// # {
|
||||
/// use rhai::{Dynamic, Array, Map, INT};
|
||||
/// use rhai::serde::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>>(
|
||||
value: &'de Dynamic,
|
||||
) -> Result<T, Box<EvalAltResult>> {
|
||||
T::deserialize(&mut DynamicDeserializer::from_dynamic(value))
|
||||
}
|
||||
|
||||
impl Error for Box<EvalAltResult> {
|
||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||
LexError::ImproperSymbol("".to_string(), err.to_string())
|
||||
.into_err(Position::NONE)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
match &self.value.0 {
|
||||
Union::Unit(_, _) => self.deserialize_unit(visitor),
|
||||
Union::Bool(_, _) => self.deserialize_bool(visitor),
|
||||
Union::Str(_, _) => self.deserialize_str(visitor),
|
||||
Union::Char(_, _) => self.deserialize_char(visitor),
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
Union::Int(_, _) => self.deserialize_i64(visitor),
|
||||
#[cfg(feature = "only_i32")]
|
||||
Union::Int(_, _) => self.deserialize_i32(visitor),
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
Union::Float(_, _) => self.deserialize_f64(visitor),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[cfg(feature = "f32_float")]
|
||||
Union::Float(_, _) => self.deserialize_f32(visitor),
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
Union::Decimal(_, _) => self.deserialize_f64(visitor),
|
||||
#[cfg(feature = "decimal")]
|
||||
#[cfg(feature = "f32_float")]
|
||||
Union::Decimal(_, _) => self.deserialize_f32(visitor),
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(_, _) => self.deserialize_seq(visitor),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(_, _) => self.deserialize_map(visitor),
|
||||
Union::FnPtr(_, _) => self.type_error(),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::TimeStamp(_, _) => self.type_error(),
|
||||
|
||||
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::<i32>() => self.deserialize_i32(visitor),
|
||||
Union::Variant(value, _) if value.is::<i64>() => self.deserialize_i64(visitor),
|
||||
Union::Variant(value, _) if value.is::<i128>() => self.deserialize_i128(visitor),
|
||||
Union::Variant(value, _) if value.is::<u8>() => self.deserialize_u8(visitor),
|
||||
Union::Variant(value, _) if value.is::<u16>() => self.deserialize_u16(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::<u128>() => self.deserialize_u128(visitor),
|
||||
|
||||
Union::Variant(_, _) => self.type_error(),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(_, _) => self.type_error(),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
visitor.visit_bool(self.value.as_bool().or_else(|_| self.type_error())?)
|
||||
}
|
||||
|
||||
fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<i8>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<i16>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else if cfg!(feature = "only_i32") {
|
||||
self.type_error()
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<i32>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else if cfg!(not(feature = "only_i32")) {
|
||||
self.type_error()
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<i64>()
|
||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x))
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else if cfg!(not(feature = "only_i32")) {
|
||||
self.type_error()
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<i128>()
|
||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_i128(x))
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<u8>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<u16>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<u32>()
|
||||
.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>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<u64>()
|
||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x))
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
if let Ok(v) = self.value.as_int() {
|
||||
self.deserialize_int(v, visitor)
|
||||
} else {
|
||||
self.value
|
||||
.downcast_ref::<u128>()
|
||||
.map_or_else(|| self.type_error(), |&x| visitor.visit_u128(x))
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_f32<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
return self
|
||||
.value
|
||||
.downcast_ref::<f32>()
|
||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f32(x));
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
{
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
return self
|
||||
.value
|
||||
.downcast_ref::<rust_decimal::Decimal>()
|
||||
.and_then(|&x| x.to_f32())
|
||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f32(v));
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(not(feature = "decimal"))]
|
||||
return self.type_error_str("f32");
|
||||
}
|
||||
|
||||
fn deserialize_f64<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
return self
|
||||
.value
|
||||
.downcast_ref::<f64>()
|
||||
.map_or_else(|| self.type_error(), |&x| _visitor.visit_f64(x));
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
{
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
return self
|
||||
.value
|
||||
.downcast_ref::<rust_decimal::Decimal>()
|
||||
.and_then(|&x| x.to_f64())
|
||||
.map_or_else(|| self.type_error(), |v| _visitor.visit_f64(v));
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(not(feature = "decimal"))]
|
||||
return self.type_error_str("f64");
|
||||
}
|
||||
|
||||
fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.value
|
||||
.downcast_ref::<char>()
|
||||
.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>> {
|
||||
self.value.downcast_ref::<ImmutableString>().map_or_else(
|
||||
|| self.type_error(),
|
||||
|x| visitor.visit_borrowed_str(x.as_str()),
|
||||
)
|
||||
}
|
||||
|
||||
fn deserialize_string<V: Visitor<'de>>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
|
||||
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
|
||||
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
|
||||
fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.value
|
||||
.downcast_ref::<()>()
|
||||
.map_or_else(|| self.type_error(), |_| visitor.visit_unit())
|
||||
}
|
||||
|
||||
fn deserialize_unit_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_unit(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_newtype_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
visitor.visit_newtype_struct(self)
|
||||
}
|
||||
|
||||
fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return self.value.downcast_ref::<Array>().map_or_else(
|
||||
|| self.type_error(),
|
||||
|arr| _visitor.visit_seq(IterateArray::new(arr.iter())),
|
||||
);
|
||||
|
||||
#[cfg(feature = "no_index")]
|
||||
return self.type_error();
|
||||
}
|
||||
|
||||
fn deserialize_tuple<V: Visitor<'de>>(
|
||||
self,
|
||||
_len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_tuple_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_seq(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return self.value.downcast_ref::<Map>().map_or_else(
|
||||
|| self.type_error(),
|
||||
|map| _visitor.visit_map(IterateMap::new(map.keys(), map.values())),
|
||||
);
|
||||
|
||||
#[cfg(feature = "no_object")]
|
||||
return self.type_error();
|
||||
}
|
||||
|
||||
fn deserialize_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_map(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
if let Ok(s) = self.value.as_str() {
|
||||
visitor.visit_enum(s.into_deserializer())
|
||||
} else {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if let Some(map) = self.value.downcast_ref::<Map>() {
|
||||
let mut iter = map.iter();
|
||||
let first = iter.next();
|
||||
let second = iter.next();
|
||||
if let (Some((key, value)), None) = (first, second) {
|
||||
visitor.visit_enum(EnumDeserializer {
|
||||
tag: &key,
|
||||
content: DynamicDeserializer::from_dynamic(value),
|
||||
})
|
||||
} else {
|
||||
self.type_error()
|
||||
}
|
||||
} else {
|
||||
self.type_error()
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return self.type_error();
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V: Visitor<'de>>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V: Visitor<'de>>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
/// `SeqAccess` implementation for arrays.
|
||||
struct IterateArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
|
||||
/// Iterator for a stream of [`Dynamic`][crate::Dynamic] values.
|
||||
iter: ITER,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateArray<'a, ITER> {
|
||||
pub fn new(iter: ITER) -> Self {
|
||||
Self { iter }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for IterateArray<'a, ITER> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn next_element_seed<T: DeserializeSeed<'de>>(
|
||||
&mut self,
|
||||
seed: T,
|
||||
) -> Result<Option<T::Value>, Box<EvalAltResult>> {
|
||||
// Deserialize each item coming out of the iterator.
|
||||
match self.iter.next() {
|
||||
None => Ok(None),
|
||||
Some(item) => seed
|
||||
.deserialize(&mut DynamicDeserializer::from_dynamic(item))
|
||||
.map(Some),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `MapAccess` implementation for maps.
|
||||
struct IterateMap<'a, KEYS, VALUES>
|
||||
where
|
||||
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||
VALUES: Iterator<Item = &'a Dynamic>,
|
||||
{
|
||||
// Iterator for a stream of [`Dynamic`][crate::Dynamic] keys.
|
||||
keys: KEYS,
|
||||
// Iterator for a stream of [`Dynamic`][crate::Dynamic] values.
|
||||
values: VALUES,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl<'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 {
|
||||
Self { keys, values }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a: 'de, 'de, KEYS, VALUES> MapAccess<'de> for IterateMap<'a, KEYS, VALUES>
|
||||
where
|
||||
KEYS: Iterator<Item = &'a ImmutableString>,
|
||||
VALUES: Iterator<Item = &'a Dynamic>,
|
||||
{
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn next_key_seed<K: DeserializeSeed<'de>>(
|
||||
&mut self,
|
||||
seed: K,
|
||||
) -> Result<Option<K::Value>, Box<EvalAltResult>> {
|
||||
// Deserialize each `ImmutableString` key coming out of the keys iterator.
|
||||
match self.keys.next() {
|
||||
None => Ok(None),
|
||||
Some(item) => seed
|
||||
.deserialize(&mut ImmutableStringDeserializer::from_str(item))
|
||||
.map(Some),
|
||||
}
|
||||
}
|
||||
|
||||
fn next_value_seed<V: DeserializeSeed<'de>>(
|
||||
&mut self,
|
||||
seed: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
// Deserialize each value item coming out of the iterator.
|
||||
seed.deserialize(&mut DynamicDeserializer::from_dynamic(
|
||||
self.values.next().unwrap(),
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
struct EnumDeserializer<'t, 'de: 't> {
|
||||
tag: &'t str,
|
||||
content: DynamicDeserializer<'de>,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl<'t, 'de> serde::de::EnumAccess<'de> for EnumDeserializer<'t, 'de> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
type Variant = Self;
|
||||
|
||||
fn variant_seed<V: DeserializeSeed<'de>>(
|
||||
self,
|
||||
seed: V,
|
||||
) -> Result<(V::Value, Self::Variant), Self::Error> {
|
||||
seed.deserialize(self.tag.into_deserializer())
|
||||
.map(|v| (v, self))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl<'t, 'de> serde::de::VariantAccess<'de> for EnumDeserializer<'t, 'de> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn unit_variant(mut self) -> Result<(), Self::Error> {
|
||||
Deserialize::deserialize(&mut self.content)
|
||||
}
|
||||
|
||||
fn newtype_variant_seed<T: DeserializeSeed<'de>>(
|
||||
mut self,
|
||||
seed: T,
|
||||
) -> Result<T::Value, Self::Error> {
|
||||
seed.deserialize(&mut self.content)
|
||||
}
|
||||
|
||||
fn tuple_variant<V: Visitor<'de>>(
|
||||
mut self,
|
||||
len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error> {
|
||||
self.content.deserialize_tuple(len, visitor)
|
||||
}
|
||||
|
||||
fn struct_variant<V: Visitor<'de>>(
|
||||
mut self,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error> {
|
||||
self.content.deserialize_struct("", fields, visitor)
|
||||
}
|
||||
}
|
165
src/serde/deserialize.rs
Normal file
165
src/serde/deserialize.rs
Normal file
@@ -0,0 +1,165 @@
|
||||
//! Implementations of [`serde::Deserialize`].
|
||||
|
||||
use crate::stdlib::{fmt, string::ToString};
|
||||
use crate::{Dynamic, ImmutableString, INT};
|
||||
use serde::de::{Deserialize, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
struct DynamicVisitor;
|
||||
|
||||
impl<'d> Visitor<'d> for DynamicVisitor {
|
||||
type Value = Dynamic;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("any type that can be converted into a Dynamic")
|
||||
}
|
||||
fn visit_bool<E: Error>(self, v: bool) -> Result<Self::Value, E> {
|
||||
Ok(v.into())
|
||||
}
|
||||
fn visit_i8<E: Error>(self, v: i8) -> Result<Self::Value, E> {
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
fn visit_i16<E: Error>(self, v: i16) -> Result<Self::Value, E> {
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
fn visit_i32<E: Error>(self, v: i32) -> Result<Self::Value, E> {
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
fn visit_i64<E: Error>(self, v: i64) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(v.into());
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.visit_i32(v as i32);
|
||||
}
|
||||
}
|
||||
fn visit_u8<E: Error>(self, v: u8) -> Result<Self::Value, E> {
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
fn visit_u16<E: Error>(self, v: u16) -> Result<Self::Value, E> {
|
||||
Ok(INT::from(v).into())
|
||||
}
|
||||
fn visit_u32<E: Error>(self, v: u32) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(INT::from(v).into());
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u32 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.visit_i32(v as i32);
|
||||
}
|
||||
}
|
||||
fn visit_u64<E: Error>(self, v: u64) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.visit_i64(v as i64);
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.visit_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
return self.visit_f64(v as f64);
|
||||
#[cfg(feature = "f32_float")]
|
||||
return Ok(v.into());
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
return Ok(v.into());
|
||||
#[cfg(feature = "f32_float")]
|
||||
return self.visit_f32(v as f32);
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
fn visit_f32<E: Error>(self, v: f32) -> Result<Self::Value, E> {
|
||||
use crate::stdlib::convert::TryFrom;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
Decimal::try_from(v)
|
||||
.map(|v| v.into())
|
||||
.map_err(Error::custom)
|
||||
}
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
fn visit_f64<E: Error>(self, v: f64) -> Result<Self::Value, E> {
|
||||
use crate::stdlib::convert::TryFrom;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
Decimal::try_from(v)
|
||||
.map(|v| v.into())
|
||||
.map_err(Error::custom)
|
||||
}
|
||||
|
||||
fn visit_char<E: Error>(self, v: char) -> Result<Self::Value, E> {
|
||||
self.visit_string(v.to_string())
|
||||
}
|
||||
fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
Ok(v.into())
|
||||
}
|
||||
fn visit_borrowed_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
|
||||
self.visit_str(v)
|
||||
}
|
||||
fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
|
||||
Ok(v.into())
|
||||
}
|
||||
|
||||
fn visit_unit<E: Error>(self) -> Result<Self::Value, E> {
|
||||
Ok(Dynamic::UNIT)
|
||||
}
|
||||
|
||||
fn visit_newtype_struct<D: Deserializer<'d>>(self, de: D) -> Result<Self::Value, D::Error> {
|
||||
Deserialize::deserialize(de)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
fn visit_seq<A: SeqAccess<'d>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
||||
let mut arr: Array = Default::default();
|
||||
|
||||
while let Some(v) = seq.next_element()? {
|
||||
arr.push(v);
|
||||
}
|
||||
|
||||
Ok(arr.into())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
fn visit_map<M: MapAccess<'d>>(self, mut map: M) -> Result<Self::Value, M::Error> {
|
||||
let mut m: Map = Default::default();
|
||||
|
||||
while let Some((k, v)) = map.next_entry()? {
|
||||
m.insert(k, v);
|
||||
}
|
||||
|
||||
Ok(m.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Deserialize<'d> for Dynamic {
|
||||
fn deserialize<D: Deserializer<'d>>(de: D) -> Result<Self, D::Error> {
|
||||
de.deserialize_any(DynamicVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> Deserialize<'d> for ImmutableString {
|
||||
fn deserialize<D: Deserializer<'d>>(de: D) -> Result<Self, D::Error> {
|
||||
let s: String = Deserialize::deserialize(de)?;
|
||||
Ok(s.into())
|
||||
}
|
||||
}
|
263
src/serde/metadata.rs
Normal file
263
src/serde/metadata.rs
Normal file
@@ -0,0 +1,263 @@
|
||||
use crate::stdlib::{
|
||||
cmp::Ordering,
|
||||
collections::BTreeMap,
|
||||
string::{String, ToString},
|
||||
vec::Vec,
|
||||
};
|
||||
use crate::{Engine, AST};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum FnType {
|
||||
Script,
|
||||
Native,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum FnNamespace {
|
||||
Global,
|
||||
Internal,
|
||||
}
|
||||
|
||||
impl From<crate::FnNamespace> for FnNamespace {
|
||||
fn from(value: crate::FnNamespace) -> Self {
|
||||
match value {
|
||||
crate::FnNamespace::Global => Self::Global,
|
||||
crate::FnNamespace::Internal => Self::Internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
enum FnAccess {
|
||||
Public,
|
||||
Private,
|
||||
}
|
||||
|
||||
impl From<crate::FnAccess> for FnAccess {
|
||||
fn from(value: crate::FnAccess) -> Self {
|
||||
match value {
|
||||
crate::FnAccess::Public => Self::Public,
|
||||
crate::FnAccess::Private => Self::Private,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Ord, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FnParam {
|
||||
pub name: String,
|
||||
#[serde(rename = "type", skip_serializing_if = "Option::is_none")]
|
||||
pub typ: Option<String>,
|
||||
}
|
||||
|
||||
impl PartialOrd for FnParam {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(match self.name.partial_cmp(&other.name).unwrap() {
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Equal => match (self.typ.is_none(), other.typ.is_none()) {
|
||||
(true, true) => Ordering::Equal,
|
||||
(true, false) => Ordering::Greater,
|
||||
(false, true) => Ordering::Less,
|
||||
(false, false) => self
|
||||
.typ
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.partial_cmp(other.typ.as_ref().unwrap())
|
||||
.unwrap(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FnMetadata {
|
||||
pub namespace: FnNamespace,
|
||||
pub access: FnAccess,
|
||||
pub name: String,
|
||||
#[serde(rename = "type")]
|
||||
pub typ: FnType,
|
||||
pub num_params: usize,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub params: Vec<FnParam>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub return_type: Option<String>,
|
||||
pub signature: String,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub doc_comments: Vec<String>,
|
||||
}
|
||||
|
||||
impl PartialOrd for FnMetadata {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(match self.name.partial_cmp(&other.name).unwrap() {
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Equal => match self.num_params.partial_cmp(&other.num_params).unwrap() {
|
||||
Ordering::Less => Ordering::Less,
|
||||
Ordering::Greater => Ordering::Greater,
|
||||
Ordering::Equal => self.params.partial_cmp(&other.params).unwrap(),
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for FnMetadata {
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.partial_cmp(other).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&crate::module::FuncInfo> for FnMetadata {
|
||||
fn from(info: &crate::module::FuncInfo) -> Self {
|
||||
Self {
|
||||
namespace: info.namespace.into(),
|
||||
access: info.access.into(),
|
||||
name: info.name.to_string(),
|
||||
typ: if info.func.is_script() {
|
||||
FnType::Script
|
||||
} else {
|
||||
FnType::Native
|
||||
},
|
||||
num_params: info.params,
|
||||
params: info
|
||||
.param_names
|
||||
.iter()
|
||||
.take(info.params)
|
||||
.map(|s| {
|
||||
let mut seg = s.splitn(2, ':');
|
||||
let name = seg
|
||||
.next()
|
||||
.map(|s| s.trim().to_string())
|
||||
.unwrap_or("_".to_string());
|
||||
let typ = seg.next().map(|s| s.trim().to_string());
|
||||
FnParam { name, typ }
|
||||
})
|
||||
.collect(),
|
||||
return_type: info
|
||||
.param_names
|
||||
.last()
|
||||
.map(|s| s.to_string())
|
||||
.or_else(|| Some("()".to_string())),
|
||||
signature: info.gen_signature(),
|
||||
doc_comments: if info.func.is_script() {
|
||||
#[cfg(feature = "no_function")]
|
||||
{
|
||||
unreachable!()
|
||||
}
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
{
|
||||
info.func.get_fn_def().comments.clone()
|
||||
}
|
||||
} else {
|
||||
Default::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::ScriptFnMetadata<'_>> for FnMetadata {
|
||||
fn from(info: crate::ScriptFnMetadata) -> Self {
|
||||
Self {
|
||||
namespace: FnNamespace::Global,
|
||||
access: info.access.into(),
|
||||
name: info.name.to_string(),
|
||||
typ: FnType::Script,
|
||||
num_params: info.params.len(),
|
||||
params: info
|
||||
.params
|
||||
.iter()
|
||||
.map(|s| FnParam {
|
||||
name: s.to_string(),
|
||||
typ: Some("Dynamic".to_string()),
|
||||
})
|
||||
.collect(),
|
||||
return_type: Some("Dynamic".to_string()),
|
||||
signature: info.to_string(),
|
||||
doc_comments: info.comments.iter().map(|s| s.to_string()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ModuleMetadata {
|
||||
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
|
||||
pub modules: BTreeMap<String, Self>,
|
||||
#[serde(skip_serializing_if = "Vec::is_empty")]
|
||||
pub functions: Vec<FnMetadata>,
|
||||
}
|
||||
|
||||
impl From<&crate::Module> for ModuleMetadata {
|
||||
fn from(module: &crate::Module) -> Self {
|
||||
let mut functions: Vec<_> = module.iter_fn().map(|f| f.into()).collect();
|
||||
functions.sort();
|
||||
|
||||
Self {
|
||||
modules: module
|
||||
.iter_sub_modules()
|
||||
.map(|(name, m)| (name.to_string(), m.as_ref().into()))
|
||||
.collect(),
|
||||
functions,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
impl Engine {
|
||||
/// _(METADATA)_ Generate a list of all functions (including those defined in an
|
||||
/// [`AST`][crate::AST]) in JSON format. Available only under the `metadata` feature.
|
||||
///
|
||||
/// Functions from the following sources are included:
|
||||
/// 1) Functions defined in an [`AST`][crate::AST]
|
||||
/// 2) Functions registered into the global namespace
|
||||
/// 3) Functions in static modules
|
||||
/// 4) Functions in global modules (optional)
|
||||
pub fn gen_fn_metadata_with_ast_to_json(
|
||||
&self,
|
||||
_ast: &AST,
|
||||
include_global: bool,
|
||||
) -> serde_json::Result<String> {
|
||||
let mut global: ModuleMetadata = Default::default();
|
||||
|
||||
if include_global {
|
||||
self.global_modules
|
||||
.iter()
|
||||
.flat_map(|m| m.iter_fn().map(|f| f.into()))
|
||||
.for_each(|info| global.functions.push(info));
|
||||
}
|
||||
|
||||
self.global_sub_modules.iter().for_each(|(name, m)| {
|
||||
global.modules.insert(name.to_string(), m.as_ref().into());
|
||||
});
|
||||
|
||||
self.global_namespace
|
||||
.iter_fn()
|
||||
.map(|f| f.into())
|
||||
.for_each(|info| global.functions.push(info));
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
_ast.iter_functions()
|
||||
.map(|f| f.into())
|
||||
.for_each(|info| global.functions.push(info));
|
||||
|
||||
global.functions.sort();
|
||||
|
||||
serde_json::to_string_pretty(&global)
|
||||
}
|
||||
|
||||
/// Generate a list of all functions in JSON format.
|
||||
/// Available only under the `metadata` feature.
|
||||
///
|
||||
/// Functions from the following sources are included:
|
||||
/// 1) Functions registered into the global namespace
|
||||
/// 2) Functions in static modules
|
||||
/// 3) Functions in global modules (optional)
|
||||
pub fn gen_fn_metadata_to_json(&self, include_global: bool) -> serde_json::Result<String> {
|
||||
self.gen_fn_metadata_with_ast_to_json(&Default::default(), include_global)
|
||||
}
|
||||
}
|
14
src/serde/mod.rs
Normal file
14
src/serde/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
//! _(SERDE)_ Serialization and deserialization support for [`serde`](https://crates.io/crates/serde).
|
||||
//! Exported under the `serde` feature only.
|
||||
|
||||
mod de;
|
||||
mod deserialize;
|
||||
mod ser;
|
||||
mod serialize;
|
||||
mod str;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
mod metadata;
|
||||
|
||||
pub use de::from_dynamic;
|
||||
pub use ser::to_dynamic;
|
697
src/serde/ser.rs
Normal file
697
src/serde/ser.rs
Normal file
@@ -0,0 +1,697 @@
|
||||
//! Implement serialization support of [`Dynamic`][crate::Dynamic] for [`serde`].
|
||||
|
||||
use crate::stdlib::{boxed::Box, fmt, string::ToString};
|
||||
use crate::{Dynamic, EvalAltResult, Position};
|
||||
use serde::ser::{
|
||||
Error, SerializeMap, SerializeSeq, SerializeStruct, SerializeTuple, SerializeTupleStruct,
|
||||
};
|
||||
use serde::{Serialize, Serializer};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Serializer for [`Dynamic`][crate::Dynamic] which is kept as a reference.
|
||||
struct DynamicSerializer {
|
||||
/// Buffer to hold a temporary key.
|
||||
_key: Dynamic,
|
||||
/// Buffer to hold a temporary value.
|
||||
_value: Dynamic,
|
||||
}
|
||||
|
||||
impl DynamicSerializer {
|
||||
/// Create a [`DynamicSerializer`] from a [`Dynamic`][crate::Dynamic] value.
|
||||
pub fn new(_value: Dynamic) -> Self {
|
||||
Self {
|
||||
_key: Default::default(),
|
||||
_value,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize a Rust type that implements [`serde::Serialize`] into a [`Dynamic`][crate::Dynamic].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # 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::serde::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["d"].read_lock::<Map>().unwrap();
|
||||
/// assert_eq!(*point["x"].read_lock::<f64>().unwrap(), 123.456);
|
||||
/// assert_eq!(*point["y"].read_lock::<f64>().unwrap(), 999.0);
|
||||
/// # }
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn to_dynamic<T: Serialize>(value: T) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut s = DynamicSerializer::new(Default::default());
|
||||
value.serialize(&mut s)
|
||||
}
|
||||
|
||||
impl Error for Box<EvalAltResult> {
|
||||
fn custom<T: fmt::Display>(err: T) -> Self {
|
||||
EvalAltResult::ErrorRuntime(err.to_string().into(), Position::NONE).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Serializer for &mut DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
type SerializeSeq = DynamicSerializer;
|
||||
type SerializeTuple = DynamicSerializer;
|
||||
type SerializeTupleStruct = DynamicSerializer;
|
||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||
type SerializeTupleVariant = TupleVariantSerializer;
|
||||
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||
type SerializeTupleVariant = serde::ser::Impossible<Dynamic, Box<EvalAltResult>>;
|
||||
type SerializeMap = DynamicSerializer;
|
||||
type SerializeStruct = DynamicSerializer;
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
type SerializeStructVariant = StructVariantSerializer;
|
||||
#[cfg(feature = "no_object")]
|
||||
type SerializeStructVariant = serde::ser::Impossible<Dynamic, Box<EvalAltResult>>;
|
||||
|
||||
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(v.into())
|
||||
}
|
||||
|
||||
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
return self.serialize_i32(i32::from(v));
|
||||
}
|
||||
|
||||
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
return self.serialize_i32(i32::from(v));
|
||||
}
|
||||
|
||||
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
return Ok(v.into());
|
||||
}
|
||||
|
||||
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return Ok(v.into());
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_i128(self, v: i128) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as i128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as i128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
return self.serialize_i32(i32::from(v));
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
return self.serialize_i32(i32::from(v));
|
||||
}
|
||||
|
||||
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
return self.serialize_i64(i64::from(v));
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u32 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u64 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_u128(self, v: u128) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
if v > i64::MAX as u128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i64(v as i64);
|
||||
}
|
||||
#[cfg(feature = "only_i32")]
|
||||
if v > i32::MAX as u128 {
|
||||
return Ok(Dynamic::from(v));
|
||||
} else {
|
||||
return self.serialize_i32(v as i32);
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
||||
return Ok(Dynamic::from(v));
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
{
|
||||
use crate::stdlib::convert::TryFrom;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
Decimal::try_from(v)
|
||||
.map(|v| v.into())
|
||||
.map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(any(not(feature = "no_float"), not(feature = "decimal")))]
|
||||
return Ok(Dynamic::from(v));
|
||||
|
||||
#[cfg(feature = "no_float")]
|
||||
#[cfg(feature = "decimal")]
|
||||
{
|
||||
use crate::stdlib::convert::TryFrom;
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
Decimal::try_from(v)
|
||||
.map(|v| v.into())
|
||||
.map_err(Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_char(self, v: char) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(v.into())
|
||||
}
|
||||
|
||||
fn serialize_str(self, v: &str) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(v.to_string().into())
|
||||
}
|
||||
|
||||
fn serialize_bytes(self, v: &[u8]) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(Dynamic::from(v.to_vec()))
|
||||
}
|
||||
|
||||
fn serialize_none(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(Dynamic::UNIT)
|
||||
}
|
||||
|
||||
fn serialize_some<T: ?Sized + Serialize>(
|
||||
self,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
value.serialize(&mut *self)
|
||||
}
|
||||
|
||||
fn serialize_unit(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
Ok(Dynamic::UNIT)
|
||||
}
|
||||
|
||||
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
self.serialize_unit()
|
||||
}
|
||||
|
||||
fn serialize_unit_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
variant: &'static str,
|
||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
self.serialize_str(variant)
|
||||
}
|
||||
|
||||
fn serialize_newtype_struct<T: ?Sized + Serialize>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
value: &T,
|
||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
value.serialize(&mut *self)
|
||||
}
|
||||
|
||||
fn serialize_newtype_variant<T: ?Sized + Serialize>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let content = to_dynamic(_value)?;
|
||||
make_variant(_variant, content)
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(DynamicSerializer::new(Array::new().into()));
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"arrays are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Box<EvalAltResult>> {
|
||||
self.serialize_seq(Some(len))
|
||||
}
|
||||
|
||||
fn serialize_tuple_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeTupleStruct, Box<EvalAltResult>> {
|
||||
self.serialize_seq(Some(len))
|
||||
}
|
||||
|
||||
fn serialize_tuple_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(TupleVariantSerializer {
|
||||
variant: _variant,
|
||||
array: Array::with_capacity(_len),
|
||||
});
|
||||
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"tuples are not supported with 'no_index' or 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(DynamicSerializer::new(Map::new().into()));
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_struct(
|
||||
self,
|
||||
_name: &'static str,
|
||||
len: usize,
|
||||
) -> Result<Self::SerializeStruct, Box<EvalAltResult>> {
|
||||
self.serialize_map(Some(len))
|
||||
}
|
||||
|
||||
fn serialize_struct_variant(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variant_index: u32,
|
||||
_variant: &'static str,
|
||||
_len: usize,
|
||||
) -> Result<Self::SerializeStructVariant, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(StructVariantSerializer {
|
||||
variant: _variant,
|
||||
map: Map::with_capacity(_len),
|
||||
});
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeSeq for DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"arrays are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
// Close the sequence.
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(self._value);
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"arrays are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeTuple for DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_element<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"tuples are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(self._value);
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"tuples are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeTupleStruct for DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"tuples are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(self._value);
|
||||
#[cfg(feature = "no_index")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"tuples are not supported with 'no_index'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeMap for DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_key<T: ?Sized + Serialize>(&mut self, _key: &T) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
self._key = _key.serialize(&mut *self)?;
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_value<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let key = crate::stdlib::mem::take(&mut self._key)
|
||||
.take_immutable_string()
|
||||
.map_err(|typ| {
|
||||
EvalAltResult::ErrorMismatchDataType(
|
||||
"string".into(),
|
||||
typ.into(),
|
||||
Position::NONE,
|
||||
)
|
||||
})?;
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
map.insert(key, _value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_key: &K,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let _key: Dynamic = _key.serialize(&mut *self)?;
|
||||
let _key = _key.take_immutable_string().map_err(|typ| {
|
||||
EvalAltResult::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
||||
})?;
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
map.insert(_key, _value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(self._value);
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializeStruct for DynamicSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
_key: &'static str,
|
||||
_value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
map.insert(_key.into(), _value);
|
||||
Ok(())
|
||||
}
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(self._value);
|
||||
#[cfg(feature = "no_object")]
|
||||
return EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
"object maps are not supported with 'no_object'".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||
struct TupleVariantSerializer {
|
||||
variant: &'static str,
|
||||
array: Array,
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||
impl serde::ser::SerializeTupleVariant for TupleVariantSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let value = to_dynamic(value)?;
|
||||
self.array.push(value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
make_variant(self.variant, self.array.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
struct StructVariantSerializer {
|
||||
variant: &'static str,
|
||||
map: Map,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl serde::ser::SerializeStructVariant for StructVariantSerializer {
|
||||
type Ok = Dynamic;
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn serialize_field<T: ?Sized + Serialize>(
|
||||
&mut self,
|
||||
key: &'static str,
|
||||
value: &T,
|
||||
) -> Result<(), Box<EvalAltResult>> {
|
||||
let value = to_dynamic(value)?;
|
||||
self.map.insert(key.into(), value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||
make_variant(self.variant, self.map.into())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
fn make_variant(variant: &'static str, value: Dynamic) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
let mut map = Map::with_capacity(1);
|
||||
map.insert(variant.into(), value);
|
||||
Ok(map.into())
|
||||
}
|
81
src/serde/serialize.rs
Normal file
81
src/serde/serialize.rs
Normal file
@@ -0,0 +1,81 @@
|
||||
//! Implementations of [`serde::Serialize`].
|
||||
|
||||
use crate::dynamic::{Union, Variant};
|
||||
use crate::stdlib::string::ToString;
|
||||
use crate::{Dynamic, ImmutableString};
|
||||
use serde::ser::{Serialize, SerializeMap, Serializer};
|
||||
|
||||
impl Serialize for Dynamic {
|
||||
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||
match &self.0 {
|
||||
Union::Unit(_, _) => ser.serialize_unit(),
|
||||
Union::Bool(x, _) => ser.serialize_bool(*x),
|
||||
Union::Str(s, _) => ser.serialize_str(s.as_str()),
|
||||
Union::Char(c, _) => ser.serialize_str(&c.to_string()),
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
Union::Int(x, _) => ser.serialize_i64(*x),
|
||||
#[cfg(feature = "only_i32")]
|
||||
Union::Int(x, _) => ser.serialize_i32(*x),
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
Union::Float(x, _) => ser.serialize_f64(**x),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[cfg(feature = "f32_float")]
|
||||
Union::Float(x, _) => ser.serialize_f32(*x),
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
#[cfg(not(feature = "f32_float"))]
|
||||
Union::Decimal(x, _) => {
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
if let Some(v) = x.to_f64() {
|
||||
ser.serialize_f64(v)
|
||||
} else {
|
||||
ser.serialize_str(&x.to_string())
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
#[cfg(feature = "f32_float")]
|
||||
Union::Decimal(x, _) => {
|
||||
use rust_decimal::prelude::ToPrimitive;
|
||||
|
||||
if let Some(v) = x.to_f32() {
|
||||
ser.serialize_f32(v)
|
||||
} else {
|
||||
ser.serialize_str(&x.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(a, _) => (**a).serialize(ser),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(m, _) => {
|
||||
let mut map = ser.serialize_map(Some(m.len()))?;
|
||||
for (k, v) in m.iter() {
|
||||
map.serialize_entry(k, v)?;
|
||||
}
|
||||
map.end()
|
||||
}
|
||||
Union::FnPtr(f, _) => ser.serialize_str(f.fn_name()),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::TimeStamp(x, _) => ser.serialize_str(x.as_ref().type_name()),
|
||||
|
||||
Union::Variant(v, _) => ser.serialize_str((***v).type_name()),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell, _) => cell.borrow().serialize(ser),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Union::Shared(cell, _) => cell.read().unwrap().serialize(ser),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for ImmutableString {
|
||||
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
|
||||
ser.serialize_str(self.as_str())
|
||||
}
|
||||
}
|
152
src/serde/str.rs
Normal file
152
src/serde/str.rs
Normal file
@@ -0,0 +1,152 @@
|
||||
//! Implement deserialization support of [`ImmutableString`][crate::ImmutableString] for [`serde`].
|
||||
|
||||
use crate::stdlib::{any::type_name, boxed::Box};
|
||||
use crate::{EvalAltResult, ImmutableString, Position};
|
||||
use serde::de::{Deserializer, Visitor};
|
||||
|
||||
/// Deserializer for `ImmutableString`.
|
||||
pub struct ImmutableStringDeserializer<'a> {
|
||||
value: &'a ImmutableString,
|
||||
}
|
||||
|
||||
impl<'a> ImmutableStringDeserializer<'a> {
|
||||
/// Create an `ImmutableStringDeserializer` from an `ImmutableString` reference.
|
||||
pub fn from_str(value: &'a ImmutableString) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
/// Shortcut for a type conversion error.
|
||||
fn type_error<T>(&self) -> Result<T, Box<EvalAltResult>> {
|
||||
EvalAltResult::ErrorMismatchOutputType(
|
||||
type_name::<T>().into(),
|
||||
"string".into(),
|
||||
Position::NONE,
|
||||
)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserializer<'de> for &mut ImmutableStringDeserializer<'de> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
fn deserialize_any<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_str(v)
|
||||
}
|
||||
fn deserialize_bool<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_i8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_i16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_i32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_i64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_u8<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_u16<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_u32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_u64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_f32<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_f64<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_char<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
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())
|
||||
}
|
||||
fn deserialize_string<V: Visitor<'de>>(
|
||||
self,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
fn deserialize_bytes<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_byte_buf<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_option<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_unit<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_unit_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_unit(v)
|
||||
}
|
||||
fn deserialize_newtype_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
v.visit_newtype_struct(self)
|
||||
}
|
||||
fn deserialize_seq<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_tuple<V: Visitor<'de>>(
|
||||
self,
|
||||
_len: usize,
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_seq(v)
|
||||
}
|
||||
fn deserialize_tuple_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_len: usize,
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_seq(v)
|
||||
}
|
||||
fn deserialize_map<V: Visitor<'de>>(self, _: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_struct<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_fields: &'static [&'static str],
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_map(v)
|
||||
}
|
||||
fn deserialize_enum<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
_: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.type_error()
|
||||
}
|
||||
fn deserialize_identifier<V: Visitor<'de>>(self, v: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_str(v)
|
||||
}
|
||||
fn deserialize_ignored_any<V: Visitor<'de>>(
|
||||
self,
|
||||
v: V,
|
||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
self.deserialize_any(v)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user