From 8bc1b25edd111df3553a39469f8bc52b6289393f Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Mon, 6 Jul 2020 15:30:33 +0800 Subject: [PATCH 1/8] 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/8] 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 46cdec12803e331358622b971e907fc00c7e5431 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 6 Jul 2020 16:20:03 +0800 Subject: [PATCH 3/8] Refine docs and tests. --- doc/src/language/loop.md | 2 +- doc/src/language/while.md | 2 +- src/api.rs | 6 +++--- tests/call_fn.rs | 2 +- tests/looping.rs | 2 +- tests/var_scope.rs | 2 +- tests/while_loop.rs | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/doc/src/language/loop.md b/doc/src/language/loop.md index b92c3f7e..e625082a 100644 --- a/doc/src/language/loop.md +++ b/doc/src/language/loop.md @@ -12,7 +12,7 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol let x = 10; loop { - x = x - 1; + x -= 1; if x > 5 { continue; } // skip to the next iteration diff --git a/doc/src/language/while.md b/doc/src/language/while.md index e912175e..5b7a5ac8 100644 --- a/doc/src/language/while.md +++ b/doc/src/language/while.md @@ -12,7 +12,7 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol let x = 10; while x > 0 { - x = x - 1; + x -= 1; if x < 6 { continue; } // skip to the next iteration print(x); if x == 5 { break; } // break out of while loop diff --git a/src/api.rs b/src/api.rs index 42805fa3..5df12aba 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1046,8 +1046,8 @@ impl Engine { /// let mut scope = Scope::new(); /// scope.push("x", 40_i64); /// - /// assert_eq!(engine.eval_with_scope::(&mut scope, "x = x + 2; x")?, 42); - /// assert_eq!(engine.eval_with_scope::(&mut scope, "x = x + 2; x")?, 44); + /// assert_eq!(engine.eval_with_scope::(&mut scope, "x += 2; x")?, 42); + /// assert_eq!(engine.eval_with_scope::(&mut scope, "x += 2; x")?, 44); /// /// // The variable in the scope is modified /// assert_eq!(scope.get_value::("x").expect("variable x should exist"), 44); @@ -1160,7 +1160,7 @@ impl Engine { /// scope.push("x", 40_i64); /// /// // Compile a script to an AST and store it for later evaluation - /// let ast = engine.compile("x = x + 2; x")?; + /// let ast = engine.compile("x += 2; x")?; /// /// // Evaluate it /// assert_eq!(engine.eval_ast_with_scope::(&mut scope, &ast)?, 42); diff --git a/tests/call_fn.rs b/tests/call_fn.rs index 690577ce..715fbc87 100644 --- a/tests/call_fn.rs +++ b/tests/call_fn.rs @@ -32,7 +32,7 @@ fn test_call_fn() -> Result<(), Box> { x + y } fn hello(x) { - x = x * foo; + x *= foo; foo = 1; x } diff --git a/tests/looping.rs b/tests/looping.rs index 3a4804ce..951f8cd7 100644 --- a/tests/looping.rs +++ b/tests/looping.rs @@ -14,7 +14,7 @@ fn test_loop() -> Result<(), Box> { if i < 10 { i += 1; if x > 20 { continue; } - x = x + i; + x += i; } else { break; } diff --git a/tests/var_scope.rs b/tests/var_scope.rs index fde83a05..0b3cc1b9 100644 --- a/tests/var_scope.rs +++ b/tests/var_scope.rs @@ -7,7 +7,7 @@ fn test_var_scope() -> Result<(), Box> { engine.eval_with_scope::<()>(&mut scope, "let x = 4 + 5")?; assert_eq!(engine.eval_with_scope::(&mut scope, "x")?, 9); - engine.eval_with_scope::<()>(&mut scope, "x = x + 1; x = x + 2;")?; + engine.eval_with_scope::<()>(&mut scope, "x += 1; x += 2;")?; assert_eq!(engine.eval_with_scope::(&mut scope, "x")?, 12); scope.set_value("x", 42 as INT); diff --git a/tests/while_loop.rs b/tests/while_loop.rs index 8916cd7c..bbcd091b 100644 --- a/tests/while_loop.rs +++ b/tests/while_loop.rs @@ -10,10 +10,10 @@ fn test_while() -> Result<(), Box> { let x = 0; while x < 10 { - x = x + 1; + x += 1; if x > 5 { break; } if x > 3 { continue; } - x = x + 3; + x += 3; } x From 0644c67252da8f76fa4b2add7b0e9d5e95ac43c8 Mon Sep 17 00:00:00 2001 From: Alvin Wong Date: Sun, 5 Jul 2020 11:43:48 +0800 Subject: [PATCH 4/8] 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 5/8] 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 6/8] 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)] From d0711394f000d5254d9a0ec215f73c95961884ff Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 6 Jul 2020 21:30:35 +0800 Subject: [PATCH 7/8] Expose FnPtr and move name checking into --- .gitignore | 4 +++- src/engine.rs | 18 ++++++------------ src/fn_native.rs | 40 ++++++++++++++++++++++++++++++++++++---- src/lib.rs | 2 +- 4 files changed, 46 insertions(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index 140811c2..e884ce0f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ target/ Cargo.lock .vscode/ .cargo/ -doc/book/ \ No newline at end of file +doc/book/ +before +after diff --git a/src/engine.rs b/src/engine.rs index e8a47960..f999235b 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -11,7 +11,7 @@ use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, St use crate::r#unsafe::unsafe_cast_var_name_to_lifetime; use crate::result::EvalAltResult; use crate::scope::{EntryType as ScopeEntryType, Scope}; -use crate::token::{is_valid_identifier, Position}; +use crate::token::Position; use crate::utils::StaticVec; #[cfg(not(feature = "no_float"))] @@ -22,6 +22,7 @@ use crate::stdlib::{ borrow::Cow, boxed::Box, collections::{HashMap, HashSet}, + convert::TryFrom, format, iter::{empty, once}, mem, @@ -1735,6 +1736,7 @@ impl Engine { let expr = args_expr.get(0); let arg_value = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; + return arg_value .take_immutable_string() .map_err(|typ| { @@ -1744,17 +1746,9 @@ impl Engine { expr.position(), )) }) - .and_then(|s| { - if is_valid_identifier(s.chars()) { - Ok(s) - } else { - Err(Box::new(EvalAltResult::ErrorFunctionNotFound( - s.to_string(), - expr.position(), - ))) - } - }) - .map(|s| FnPtr::from(s).into()); + .and_then(|s| FnPtr::try_from(s)) + .map(Into::::into) + .map_err(|err| err.new_position(*pos)); } } diff --git a/src/fn_native.rs b/src/fn_native.rs index 49cb4570..be4d6593 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -3,9 +3,10 @@ use crate::engine::Engine; use crate::module::Module; use crate::parser::ScriptFnDef; use crate::result::EvalAltResult; +use crate::token::{is_valid_identifier, Position}; use crate::utils::ImmutableString; -use crate::stdlib::{boxed::Box, fmt, rc::Rc, sync::Arc}; +use crate::stdlib::{boxed::Box, convert::TryFrom, fmt, rc::Rc, sync::Arc}; /// Trait that maps to `Send + Sync` only under the `sync` feature. #[cfg(feature = "sync")] @@ -52,6 +53,10 @@ pub type FnCallArgs<'a> = [&'a mut Dynamic]; pub struct FnPtr(ImmutableString); impl FnPtr { + /// Create a new function pointer. + pub(crate) fn new>(name: S) -> Self { + Self(name.into()) + } /// Get the name of the function. pub fn fn_name(&self) -> &str { self.get_fn_name().as_ref() @@ -72,9 +77,36 @@ impl fmt::Display for FnPtr { } } -impl> From for FnPtr { - fn from(value: S) -> Self { - Self(value.into()) +impl TryFrom for FnPtr { + type Error = Box; + + fn try_from(value: ImmutableString) -> Result { + if is_valid_identifier(value.chars()) { + Ok(Self(value)) + } else { + Err(Box::new(EvalAltResult::ErrorFunctionNotFound( + value.to_string(), + Position::none(), + ))) + } + } +} + +impl TryFrom for FnPtr { + type Error = Box; + + fn try_from(value: String) -> Result { + let s: ImmutableString = value.into(); + Self::try_from(s) + } +} + +impl TryFrom<&str> for FnPtr { + type Error = Box; + + fn try_from(value: &str) -> Result { + let s: ImmutableString = value.into(); + Self::try_from(s) } } diff --git a/src/lib.rs b/src/lib.rs index 13221e2c..768ad25a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ mod utils; pub use any::Dynamic; pub use engine::Engine; pub use error::{ParseError, ParseErrorType}; -pub use fn_native::IteratorFn; +pub use fn_native::{FnPtr, IteratorFn}; pub use fn_register::{RegisterFn, RegisterResultFn}; pub use module::Module; pub use parser::{ImmutableString, AST, INT}; From a2c0554f3c5556a2ca4f8f004c4fb46929b2a7d3 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 6 Jul 2020 21:52:07 +0800 Subject: [PATCH 8/8] Make consistent style. --- tests/serde.rs | 125 +++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 83 deletions(-) diff --git a/tests/serde.rs b/tests/serde.rs index 7b0a4c5f..005e4e8c 100644 --- a/tests/serde.rs +++ b/tests/serde.rs @@ -10,57 +10,33 @@ use rhai::Map; #[test] fn test_serde_ser_primary_types() -> Result<(), Box> { - assert_eq!( - to_dynamic(42_u64)?.type_name(), - std::any::type_name::() - ); - assert_eq!(to_dynamic(u64::MAX)?.type_name(), "u64"); - assert_eq!( - to_dynamic(42 as INT)?.type_name(), - std::any::type_name::() - ); - assert_eq!(to_dynamic(true)?.type_name(), "bool"); - assert_eq!(to_dynamic(())?.type_name(), "()"); + assert!(to_dynamic(42_u64)?.is::()); + assert!(to_dynamic(u64::MAX)?.is::()); + assert!(to_dynamic(42 as INT)?.is::()); + assert!(to_dynamic(true)?.is::()); + assert!(to_dynamic(())?.is::<()>()); #[cfg(not(feature = "no_float"))] { - assert_eq!(to_dynamic(123.456_f64)?.type_name(), "f64"); - assert_eq!(to_dynamic(123.456_f32)?.type_name(), "f32"); + assert!(to_dynamic(123.456_f64)?.is::()); + assert!(to_dynamic(123.456_f32)?.is::()); } - assert_eq!(to_dynamic("hello".to_string())?.type_name(), "string"); + assert!(to_dynamic("hello".to_string())?.is::()); 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::() - ); + assert!(to_dynamic(42_i8)?.is::()); + assert!(to_dynamic(42_i16)?.is::()); + assert!(to_dynamic(42_i32)?.is::()); + assert!(to_dynamic(42_i64)?.is::()); + assert!(to_dynamic(42_u8)?.is::()); + assert!(to_dynamic(42_u16)?.is::()); + assert!(to_dynamic(42_u32)?.is::()); + assert!(to_dynamic(42_u64)?.is::()); Ok(()) } @@ -72,7 +48,7 @@ fn test_serde_ser_array() -> Result<(), Box> { let d = to_dynamic(arr)?; assert!(d.is::()); - assert_eq!(d.cast::().len(), 4); + assert_eq!(4, d.cast::().len()); Ok(()) } @@ -105,14 +81,14 @@ fn test_serde_ser_struct() -> Result<(), Box> { assert!(d.is::()); let mut map = d.cast::(); - let mut obj = map.remove("obj").unwrap().cast::(); - let mut seq = map.remove("seq").unwrap().cast::(); + let obj = map.remove("obj").unwrap().cast::(); + let seq = map.remove("seq").unwrap().cast::(); - assert_eq!(obj.remove("a").unwrap().cast::(), 123); - assert!(obj.remove("b").unwrap().cast::()); - assert_eq!(map.remove("int").unwrap().cast::(), 42); + assert_eq!(Ok(123), obj["a"].as_int()); + assert!(obj["b"].as_bool().unwrap()); + assert_eq!(Ok(42), map["int"].as_int()); assert_eq!(seq.len(), 3); - assert_eq!(seq.remove(1).cast::(), "kitty"); + assert_eq!(Ok("kitty"), seq[1].as_str()); Ok(()) } @@ -126,10 +102,10 @@ fn test_serde_ser_unit_enum() -> Result<(), Box> { } let d = to_dynamic(MyEnum::VariantFoo)?; - assert_eq!("VariantFoo", d.as_str().unwrap()); + assert_eq!(Ok("VariantFoo"), d.as_str()); let d = to_dynamic(MyEnum::VariantBar)?; - assert_eq!("VariantBar", d.as_str().unwrap()); + assert_eq!(Ok("VariantBar"), d.as_str()); Ok(()) } @@ -152,22 +128,19 @@ fn test_serde_ser_externally_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantUnit)?; - assert_eq!("VariantUnit", d.as_str().unwrap()); + assert_eq!(Ok("VariantUnit"), to_dynamic(MyEnum::VariantUnit)?.as_str()); } #[cfg(not(feature = "no_index"))] { - let d = to_dynamic(MyEnum::VariantUnitTuple())?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantUnitTuple())?.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 mut map = to_dynamic(MyEnum::VariantNewtype(123))?.cast::(); let content = map.remove("VariantNewtype").unwrap(); assert!(map.is_empty()); assert_eq!(Ok(123), content.as_int()); @@ -175,8 +148,7 @@ fn test_serde_ser_externally_tagged_enum() -> Result<(), Box> { #[cfg(not(feature = "no_index"))] { - let d = to_dynamic(MyEnum::VariantTuple(123, 456))?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantTuple(123, 456))?.cast::(); let content = map.remove("VariantTuple").unwrap().cast::(); assert!(map.is_empty()); assert_eq!(2, content.len()); @@ -185,16 +157,14 @@ fn test_serde_ser_externally_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.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 = to_dynamic(MyEnum::VariantStruct { a: 123 })?.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()); @@ -214,16 +184,14 @@ fn test_serde_ser_internally_tagged_enum() -> Result<(), Box> { VariantStruct { a: i32 }, } - let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.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::(); + let mut map = to_dynamic(MyEnum::VariantStruct { a: 123 })?.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()); @@ -250,16 +218,14 @@ fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantUnit)?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantUnit)?.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::(); + let mut map = to_dynamic(MyEnum::VariantUnitTuple())?.cast::(); assert_eq!(Ok("VariantUnitTuple"), map.remove("tag").unwrap().as_str()); let content = map.remove("content").unwrap().cast::(); assert!(map.is_empty()); @@ -267,8 +233,7 @@ fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantNewtype(123))?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantNewtype(123))?.cast::(); assert_eq!(Ok("VariantNewtype"), map.remove("tag").unwrap().as_str()); let content = map.remove("content").unwrap(); assert!(map.is_empty()); @@ -277,8 +242,7 @@ fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { #[cfg(not(feature = "no_index"))] { - let d = to_dynamic(MyEnum::VariantTuple(123, 456))?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantTuple(123, 456))?.cast::(); assert_eq!(Ok("VariantTuple"), map.remove("tag").unwrap().as_str()); let content = map.remove("content").unwrap().cast::(); assert!(map.is_empty()); @@ -288,8 +252,7 @@ fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::(); assert_eq!( Ok("VariantEmptyStruct"), map.remove("tag").unwrap().as_str() @@ -300,8 +263,7 @@ fn test_serde_ser_adjacently_tagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantStruct { a: 123 })?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantStruct { a: 123 })?.cast::(); assert_eq!(Ok("VariantStruct"), map.remove("tag").unwrap().as_str()); let mut map_inner = map.remove("content").unwrap().cast::(); assert!(map.is_empty()); @@ -324,21 +286,18 @@ fn test_serde_ser_untagged_enum() -> Result<(), Box> { } { - let d = to_dynamic(MyEnum::VariantEmptyStruct {})?; - let map = d.cast::(); + let map = to_dynamic(MyEnum::VariantEmptyStruct {})?.cast::(); assert!(map.is_empty()); } { - let d = to_dynamic(MyEnum::VariantStruct1 { a: 123 })?; - let mut map = d.cast::(); + let mut map = to_dynamic(MyEnum::VariantStruct1 { a: 123 })?.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::(); + let mut map = to_dynamic(MyEnum::VariantStruct2 { b: 123 })?.cast::(); assert_eq!(Ok(123), map.remove("b").unwrap().as_int()); assert!(map.is_empty()); }