From 8bc1b25edd111df3553a39469f8bc52b6289393f Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Mon, 6 Jul 2020 15:30:33 +0800 Subject: [PATCH 1/5] Fix `only_i32` build --- src/serde/ser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 1477da2d..79b1b733 100644 --- a/src/serde/ser.rs +++ b/src/serde/ser.rs @@ -162,7 +162,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); From 8f53ce50d47c9cc965ba03a6be853d063eb88e05 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Sun, 5 Jul 2020 11:35:50 +0800 Subject: [PATCH 2/5] Ensure rhai::INT can be deserialized into any integer types --- src/serde/de.rs | 98 +++++++++++++++++++++++++++++++++++++------------ tests/serde.rs | 46 +++++++++++++++++++++++ 2 files changed, 120 insertions(+), 24 deletions(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index 82910073..f91c051d 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -49,6 +49,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 +173,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> { diff --git a/tests/serde.rs b/tests/serde.rs index 82ec330b..95a3c24e 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> { @@ -106,6 +138,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> { From 0644c67252da8f76fa4b2add7b0e9d5e95ac43c8 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Sun, 5 Jul 2020 11:43:48 +0800 Subject: [PATCH 3/5] Impl. deserializing `enum` representations --- src/serde/de.rs | 84 +++++++++++++++- tests/serde.rs | 258 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 339 insertions(+), 3 deletions(-) diff --git a/src/serde/de.rs b/src/serde/de.rs index f91c051d..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"))] @@ -384,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>( @@ -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; + 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/tests/serde.rs b/tests/serde.rs index 95a3c24e..1d509eea 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -236,3 +236,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(()) +} From 4b6afc9c727295ebcd06b12f29a56c61eb3cc9f6 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Mon, 6 Jul 2020 16:11:54 +0800 Subject: [PATCH 4/5] Add `enum` serialization tests --- tests/serde.rs | 230 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/tests/serde.rs b/tests/serde.rs index 1d509eea..cf86dcf2 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -117,6 +117,236 @@ 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] +#[ignore = "failing 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))?); From 4a3a32dc3aee55009b39954037ea453c8a256d0d Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Mon, 6 Jul 2020 18:31:23 +0800 Subject: [PATCH 5/5] Fix serializing externally-tagged `enum` representations --- src/serde/ser.rs | 143 +++++++++++++++++++++++++++++++---------------- tests/serde.rs | 1 - 2 files changed, 94 insertions(+), 50 deletions(-) diff --git a/src/serde/ser.rs b/src/serde/ser.rs index 79b1b733..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()) @@ -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 cf86dcf2..7b0a4c5f 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -135,7 +135,6 @@ fn test_serde_ser_unit_enum() -> Result<(), Box> { } #[test] -#[ignore = "failing test"] #[cfg(not(feature = "no_object"))] fn test_serde_ser_externally_tagged_enum() -> Result<(), Box> { #[derive(Serialize)]