Impl. deserializing enum
representations
This commit is contained in:
parent
8f53ce50d4
commit
0644c67252
@ -7,7 +7,10 @@ use crate::result::EvalAltResult;
|
|||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::ImmutableString;
|
use crate::utils::ImmutableString;
|
||||||
|
|
||||||
use serde::de::{DeserializeSeed, Deserializer, Error, MapAccess, SeqAccess, Visitor};
|
use serde::de::{
|
||||||
|
DeserializeSeed, Deserializer, EnumAccess, Error, IntoDeserializer, MapAccess, SeqAccess,
|
||||||
|
VariantAccess, Visitor,
|
||||||
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -384,10 +387,31 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
self,
|
self,
|
||||||
_name: &'static str,
|
_name: &'static str,
|
||||||
_variants: &'static [&'static str],
|
_variants: &'static [&'static str],
|
||||||
_: V,
|
visitor: V,
|
||||||
) -> Result<V::Value, Box<EvalAltResult>> {
|
) -> 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()
|
self.type_error()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
self.type_error()
|
||||||
|
}
|
||||||
|
#[cfg(feature = "no_object")]
|
||||||
|
return self.type_error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn deserialize_identifier<V: Visitor<'de>>(
|
fn deserialize_identifier<V: Visitor<'de>>(
|
||||||
self,
|
self,
|
||||||
@ -494,3 +518,57 @@ where
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
struct EnumDeserializer<'t, 'de: 't> {
|
||||||
|
tag: &'t str,
|
||||||
|
content: DynamicDeserializer<'de>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl<'t, 'de> EnumAccess<'de> for EnumDeserializer<'t, 'de> {
|
||||||
|
type Error = Box<EvalAltResult>;
|
||||||
|
type Variant = Self;
|
||||||
|
|
||||||
|
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||||
|
where
|
||||||
|
V: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(self.tag.into_deserializer())
|
||||||
|
.map(|v| (v, self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
impl<'t, '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>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||||
|
where
|
||||||
|
T: DeserializeSeed<'de>,
|
||||||
|
{
|
||||||
|
seed.deserialize(&mut self.content)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.content.deserialize_tuple(len, visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn struct_variant<V>(
|
||||||
|
mut self,
|
||||||
|
fields: &'static [&'static str],
|
||||||
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error>
|
||||||
|
where
|
||||||
|
V: Visitor<'de>,
|
||||||
|
{
|
||||||
|
self.content.deserialize_struct("", fields, visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
258
tests/serde.rs
258
tests/serde.rs
@ -236,3 +236,261 @@ fn test_serde_de_script() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_serde_de_unit_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantFoo,
|
||||||
|
VariantBar,
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantFoo".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantFoo, from_dynamic(&d)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantBar".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantBar, from_dynamic(&d)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_externally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let d = Dynamic::from("VariantUnit".to_string());
|
||||||
|
assert_eq!(MyEnum::VariantUnit, from_dynamic(&d).unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantUnitTuple".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnitTuple(),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantNewtype".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantNewtype(123),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![(123 as INT).into(), (456 as INT).into()];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantTuple".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantTuple(123, 456),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map_inner = Map::new();
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantEmptyStruct".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_inner = Map::new();
|
||||||
|
map_inner.insert("a".into(), (123 as INT).into());
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("VariantStruct".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_internally_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "tag", deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct { a: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("tag".into(), "VariantStruct".into());
|
||||||
|
map.insert("a".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("tag".into(), "VariantEmptyStruct".into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_adjacently_tagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(tag = "tag", content = "content", deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantUnit,
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantUnitTuple(),
|
||||||
|
VariantNewtype(i32),
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
VariantTuple(i32, i32),
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct {
|
||||||
|
a: i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantUnit".into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnit,
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantUnitTuple".into());
|
||||||
|
map_outer.insert("content".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantUnitTuple(),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantNewtype".into());
|
||||||
|
map_outer.insert("content".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantNewtype(123),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
{
|
||||||
|
let array: Array = vec![(123 as INT).into(), (456 as INT).into()];
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantTuple".into());
|
||||||
|
map_outer.insert("content".into(), array.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantTuple(123, 456),
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map_inner = Map::new();
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantEmptyStruct".into());
|
||||||
|
map_outer.insert("content".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map_inner = Map::new();
|
||||||
|
map_inner.insert("a".into(), (123 as INT).into());
|
||||||
|
let mut map_outer = Map::new();
|
||||||
|
map_outer.insert("tag".into(), "VariantStruct".into());
|
||||||
|
map_outer.insert("content".into(), map_inner.into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct { a: 123 },
|
||||||
|
from_dynamic(&map_outer.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
fn test_serde_de_untagged_enum() -> Result<(), Box<EvalAltResult>> {
|
||||||
|
#[derive(Debug, PartialEq, Deserialize)]
|
||||||
|
#[serde(untagged, deny_unknown_fields)]
|
||||||
|
enum MyEnum {
|
||||||
|
VariantEmptyStruct {},
|
||||||
|
VariantStruct1 { a: i32 },
|
||||||
|
VariantStruct2 { b: i32 },
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let map = Map::new();
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantEmptyStruct {},
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("a".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct1 { a: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut map = Map::new();
|
||||||
|
map.insert("b".into(), (123 as INT).into());
|
||||||
|
assert_eq!(
|
||||||
|
MyEnum::VariantStruct2 { b: 123 },
|
||||||
|
from_dynamic(&map.into()).unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user