diff --git a/src/serde/de.rs b/src/serde/de.rs index 82910073..88533718 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -7,7 +7,10 @@ use crate::result::EvalAltResult; use crate::token::Position; 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; #[cfg(not(feature = "no_index"))] @@ -49,6 +52,20 @@ impl<'de> DynamicDeserializer<'de> { Position::none(), ))) } + fn deserialize_int>( + &mut self, + v: crate::INT, + visitor: V, + ) -> Result> { + #[cfg(not(feature = "only_i32"))] + { + visitor.visit_i64(v) + } + #[cfg(feature = "only_i32")] + { + visitor.visit_i32(v) + } + } } /// Deserialize a `Dynamic` value into a Rust type that implements `serde::Deserialize`. @@ -159,51 +176,87 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { } fn deserialize_i8>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_i8(x)) + } } fn deserialize_i16>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_i16(x)) + } } fn deserialize_i32>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x)) + 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::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_i32(x)) + } } fn deserialize_i64>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x)) + 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::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_i64(x)) + } } fn deserialize_u8>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_u8(x)) + } } fn deserialize_u16>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_u16(x)) + } } fn deserialize_u32>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_u32(x)) + } } fn deserialize_u64>(self, visitor: V) -> Result> { - self.value - .downcast_ref::() - .map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x)) + if let Ok(v) = self.value.as_int() { + self.deserialize_int(v, visitor) + } else { + self.value + .downcast_ref::() + .map_or_else(|| self.type_error(), |&x| visitor.visit_u64(x)) + } } fn deserialize_f32>(self, visitor: V) -> Result> { @@ -334,9 +387,30 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { self, _name: &'static str, _variants: &'static [&'static str], - _: V, + visitor: V, ) -> Result> { - self.type_error() + 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::() { + 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>( @@ -444,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; + type Variant = Self; + + fn variant_seed(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; + + fn unit_variant(mut self) -> Result<(), Self::Error> { + Deserialize::deserialize(&mut self.content) + } + + fn newtype_variant_seed(mut self, seed: T) -> Result + where + T: DeserializeSeed<'de>, + { + seed.deserialize(&mut self.content) + } + + fn tuple_variant(mut self, len: usize, visitor: V) -> Result + where + V: Visitor<'de>, + { + self.content.deserialize_tuple(len, visitor) + } + + fn struct_variant( + mut self, + fields: &'static [&'static str], + visitor: V, + ) -> Result + where + V: Visitor<'de>, + { + self.content.deserialize_struct("", fields, visitor) + } +} diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 1477da2d..181573b0 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -103,10 +103,16 @@ impl Serializer for &mut DynamicSerializer { type SerializeSeq = DynamicSerializer; type SerializeTuple = DynamicSerializer; type SerializeTupleStruct = DynamicSerializer; - type SerializeTupleVariant = 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>; type SerializeMap = DynamicSerializer; type SerializeStruct = DynamicSerializer; - type SerializeStructVariant = DynamicSerializer; + #[cfg(not(feature = "no_object"))] + type SerializeStructVariant = StructVariantSerializer; + #[cfg(feature = "no_object")] + type SerializeStructVariant = serde::ser::Impossible>; fn serialize_bool(self, v: bool) -> Result> { Ok(v.into()) @@ -162,7 +168,7 @@ impl Serializer for &mut DynamicSerializer { #[cfg(not(feature = "only_i32"))] return self.serialize_i64(i64::from(v)); #[cfg(feature = "only_i32")] - if v > i32::MAX as u64 { + if v > i32::MAX as u32 { return Ok(Dynamic::from(v)); } else { return self.serialize_i32(v as i32); @@ -244,10 +250,20 @@ impl Serializer for &mut DynamicSerializer { self, _name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, value: &T, ) -> Result> { - value.serialize(&mut *self) + #[cfg(not(feature = "no_object"))] + { + let content = to_dynamic(value)?; + make_variant(variant, content) + } + #[cfg(feature = "no_object")] + return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + "Dynamic".into(), + "map".into(), + Position::none(), + ))); } fn serialize_seq(self, _len: Option) -> Result> { @@ -277,10 +293,26 @@ impl Serializer for &mut DynamicSerializer { self, _name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, len: usize, ) -> Result> { - self.serialize_seq(Some(len)) + #[cfg(not(any(feature = "no_object", feature = "no_index")))] + return Ok(TupleVariantSerializer { + variant, + array: Array::with_capacity(len), + }); + #[cfg(any(feature = "no_object", feature = "no_index"))] + { + #[cfg(feature = "no_object")] + let err_type = "map"; + #[cfg(not(feature = "no_object"))] + let err_type = "array"; + Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + "Dynamic".into(), + err_type.into(), + Position::none(), + ))) + } } fn serialize_map(self, _len: Option) -> Result> { @@ -306,10 +338,20 @@ impl Serializer for &mut DynamicSerializer { self, _name: &'static str, _variant_index: u32, - _variant: &'static str, + variant: &'static str, len: usize, ) -> Result> { - self.serialize_map(Some(len)) + #[cfg(not(feature = "no_object"))] + return Ok(StructVariantSerializer { + variant, + map: Map::with_capacity(len), + }); + #[cfg(feature = "no_object")] + return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( + "Dynamic".into(), + "map".into(), + Position::none(), + ))); } } @@ -395,33 +437,6 @@ impl SerializeTupleStruct for DynamicSerializer { } } -impl SerializeTupleVariant for DynamicSerializer { - type Ok = Dynamic; - type Error = Box; - - fn serialize_field( - &mut self, - value: &T, - ) -> Result<(), Box> { - #[cfg(not(feature = "no_index"))] - { - let value = value.serialize(&mut *self)?; - let arr = self.value.downcast_mut::().unwrap(); - arr.push(value); - Ok(()) - } - #[cfg(feature = "no_index")] - unreachable!() - } - - fn end(self) -> Result> { - #[cfg(not(feature = "no_index"))] - return Ok(self.value); - #[cfg(feature = "no_index")] - unreachable!() - } -} - impl SerializeMap for DynamicSerializer { type Ok = Dynamic; type Error = Box; @@ -520,7 +535,39 @@ impl SerializeStruct for DynamicSerializer { } } -impl SerializeStructVariant for DynamicSerializer { +#[cfg(not(any(feature = "no_object", feature = "no_index")))] +pub struct TupleVariantSerializer { + variant: &'static str, + array: Array, +} + +#[cfg(not(any(feature = "no_object", feature = "no_index")))] +impl SerializeTupleVariant for TupleVariantSerializer { + type Ok = Dynamic; + type Error = Box; + + fn serialize_field( + &mut self, + value: &T, + ) -> Result<(), Box> { + let value = to_dynamic(value)?; + self.array.push(value); + Ok(()) + } + + fn end(self) -> Result> { + make_variant(self.variant, self.array.into()) + } +} + +#[cfg(not(feature = "no_object"))] +pub struct StructVariantSerializer { + variant: &'static str, + map: Map, +} + +#[cfg(not(feature = "no_object"))] +impl SerializeStructVariant for StructVariantSerializer { type Ok = Dynamic; type Error = Box; @@ -529,21 +576,19 @@ impl SerializeStructVariant for DynamicSerializer { key: &'static str, value: &T, ) -> Result<(), Box> { - #[cfg(not(feature = "no_object"))] - { - let value = value.serialize(&mut *self)?; - let map = self.value.downcast_mut::().unwrap(); - map.insert(key.into(), value); - Ok(()) - } - #[cfg(feature = "no_object")] - unreachable!() + let value = to_dynamic(value)?; + self.map.insert(key.into(), value); + Ok(()) } fn end(self) -> Result> { - #[cfg(not(feature = "no_object"))] - return Ok(self.value); - #[cfg(feature = "no_object")] - unreachable!() + make_variant(self.variant, self.map.into()) } } + +#[cfg(not(feature = "no_object"))] +fn make_variant(variant: &'static str, value: Dynamic) -> Result> { + let mut map = Map::with_capacity(1); + map.insert(variant.into(), value); + Ok(map.into()) +} diff --git a/tests/serde.rs b/tests/serde.rs index 82ec330b..7b0a4c5f 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -33,6 +33,38 @@ fn test_serde_ser_primary_types() -> Result<(), Box> { Ok(()) } +#[test] +fn test_serde_ser_integer_types() -> Result<(), Box> { + assert_eq!(to_dynamic(42_i8)?.type_name(), std::any::type_name::()); + assert_eq!( + to_dynamic(42_i16)?.type_name(), + std::any::type_name::() + ); + assert_eq!( + to_dynamic(42_i32)?.type_name(), + std::any::type_name::() + ); + assert_eq!( + to_dynamic(42_i64)?.type_name(), + std::any::type_name::() + ); + assert_eq!(to_dynamic(42_u8)?.type_name(), std::any::type_name::()); + assert_eq!( + to_dynamic(42_u16)?.type_name(), + std::any::type_name::() + ); + assert_eq!( + to_dynamic(42_u32)?.type_name(), + std::any::type_name::() + ); + assert_eq!( + to_dynamic(42_u64)?.type_name(), + std::any::type_name::() + ); + + Ok(()) +} + #[test] #[cfg(not(feature = "no_index"))] fn test_serde_ser_array() -> Result<(), Box> { @@ -85,6 +117,235 @@ fn test_serde_ser_struct() -> Result<(), Box> { Ok(()) } +#[test] +fn test_serde_ser_unit_enum() -> Result<(), Box> { + #[derive(Serialize)] + enum MyEnum { + VariantFoo, + VariantBar, + } + + let d = to_dynamic(MyEnum::VariantFoo)?; + assert_eq!("VariantFoo", d.as_str().unwrap()); + + let d = to_dynamic(MyEnum::VariantBar)?; + assert_eq!("VariantBar", d.as_str().unwrap()); + + Ok(()) +} + +#[test] +#[cfg(not(feature = "no_object"))] +fn test_serde_ser_externally_tagged_enum() -> Result<(), Box> { + #[derive(Serialize)] + 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 = to_dynamic(MyEnum::VariantUnit)?; + assert_eq!("VariantUnit", d.as_str().unwrap()); + } + + #[cfg(not(feature = "no_index"))] + { + let d = to_dynamic(MyEnum::VariantUnitTuple())?; + let mut map = d.cast::(); + let content = map.remove("VariantUnitTuple").unwrap().cast::(); + assert!(map.is_empty()); + assert!(content.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantNewtype(123))?; + let mut map = d.cast::(); + let content = map.remove("VariantNewtype").unwrap(); + assert!(map.is_empty()); + assert_eq!(Ok(123), content.as_int()); + } + + #[cfg(not(feature = "no_index"))] + { + let d = to_dynamic(MyEnum::VariantTuple(123, 456))?; + let mut map = d.cast::(); + let content = map.remove("VariantTuple").unwrap().cast::(); + assert!(map.is_empty()); + assert_eq!(2, content.len()); + assert_eq!(Ok(123), content[0].as_int()); + assert_eq!(Ok(456), content[1].as_int()); + } + + { + let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; + let mut map = d.cast::(); + let map_inner = map.remove("VariantEmptyStruct").unwrap().cast::(); + assert!(map.is_empty()); + assert!(map_inner.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantStruct { a: 123 })?; + let mut map = d.cast::(); + let mut map_inner = map.remove("VariantStruct").unwrap().cast::(); + assert!(map.is_empty()); + assert_eq!(Ok(123), map_inner.remove("a").unwrap().as_int()); + assert!(map_inner.is_empty()); + } + + Ok(()) +} + +#[test] +#[cfg(not(feature = "no_object"))] +fn test_serde_ser_internally_tagged_enum() -> Result<(), Box> { + #[derive(Serialize)] + #[serde(tag = "tag")] + enum MyEnum { + VariantEmptyStruct {}, + VariantStruct { a: i32 }, + } + + let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; + let mut map = d.cast::(); + assert_eq!( + Ok("VariantEmptyStruct"), + map.remove("tag").unwrap().as_str() + ); + assert!(map.is_empty()); + + let d = to_dynamic(MyEnum::VariantStruct { a: 123 })?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantStruct"), map.remove("tag").unwrap().as_str()); + assert_eq!(Ok(123), map.remove("a").unwrap().as_int()); + assert!(map.is_empty()); + + Ok(()) +} + +#[test] +#[cfg(not(feature = "no_object"))] +fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { + #[derive(Serialize)] + #[serde(tag = "tag", content = "content")] + 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 = to_dynamic(MyEnum::VariantUnit)?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantUnit"), map.remove("tag").unwrap().as_str()); + assert!(map.is_empty()); + } + + #[cfg(not(feature = "no_index"))] + { + let d = to_dynamic(MyEnum::VariantUnitTuple())?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantUnitTuple"), map.remove("tag").unwrap().as_str()); + let content = map.remove("content").unwrap().cast::(); + assert!(map.is_empty()); + assert!(content.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantNewtype(123))?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantNewtype"), map.remove("tag").unwrap().as_str()); + let content = map.remove("content").unwrap(); + assert!(map.is_empty()); + assert_eq!(Ok(123), content.as_int()); + } + + #[cfg(not(feature = "no_index"))] + { + let d = to_dynamic(MyEnum::VariantTuple(123, 456))?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantTuple"), map.remove("tag").unwrap().as_str()); + let content = map.remove("content").unwrap().cast::(); + assert!(map.is_empty()); + assert_eq!(2, content.len()); + assert_eq!(Ok(123), content[0].as_int()); + assert_eq!(Ok(456), content[1].as_int()); + } + + { + let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; + let mut map = d.cast::(); + assert_eq!( + Ok("VariantEmptyStruct"), + map.remove("tag").unwrap().as_str() + ); + let map_inner = map.remove("content").unwrap().cast::(); + assert!(map.is_empty()); + assert!(map_inner.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantStruct { a: 123 })?; + let mut map = d.cast::(); + assert_eq!(Ok("VariantStruct"), map.remove("tag").unwrap().as_str()); + let mut map_inner = map.remove("content").unwrap().cast::(); + assert!(map.is_empty()); + assert_eq!(Ok(123), map_inner.remove("a").unwrap().as_int()); + assert!(map_inner.is_empty()); + } + + Ok(()) +} + +#[test] +#[cfg(not(feature = "no_object"))] +fn test_serde_ser_untagged_enum() -> Result<(), Box> { + #[derive(Serialize)] + #[serde(untagged)] + enum MyEnum { + VariantEmptyStruct {}, + VariantStruct1 { a: i32 }, + VariantStruct2 { b: i32 }, + } + + { + let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; + let map = d.cast::(); + assert!(map.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantStruct1 { a: 123 })?; + let mut map = d.cast::(); + assert_eq!(Ok(123), map.remove("a").unwrap().as_int()); + assert!(map.is_empty()); + } + + { + let d = to_dynamic(MyEnum::VariantStruct2 { b: 123 })?; + let mut map = d.cast::(); + assert_eq!(Ok(123), map.remove("b").unwrap().as_int()); + assert!(map.is_empty()); + } + + Ok(()) +} + #[test] fn test_serde_de_primary_types() -> Result<(), Box> { assert_eq!(42_u16, from_dynamic(&Dynamic::from(42_u16))?); @@ -106,6 +367,20 @@ fn test_serde_de_primary_types() -> Result<(), Box> { Ok(()) } +#[test] +fn test_serde_de_integer_types() -> Result<(), Box> { + assert_eq!(42_i8, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_i16, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_i32, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_i64, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_u8, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_u16, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_u32, from_dynamic(&Dynamic::from(42 as INT))?); + assert_eq!(42_u64, from_dynamic(&Dynamic::from(42 as INT))?); + + Ok(()) +} + #[test] #[cfg(not(feature = "no_index"))] fn test_serde_de_array() -> Result<(), Box> { @@ -190,3 +465,261 @@ fn test_serde_de_script() -> Result<(), Box> { Ok(()) } + +#[test] +fn test_serde_de_unit_enum() -> Result<(), Box> { + #[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> { + #[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> { + #[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> { + #[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> { + #[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(()) +}