From 1cda1f71a7bab877929bf43f30f9c2dd8676640e Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Sun, 8 Mar 2015 19:07:23 -0700 Subject: [PATCH] Implement #[derive_deserialize] for generic enums --- serde2/serde2_macros/src/lib.rs | 83 +++++++++++++----- serde2/tests/test_macros.rs | 146 +++++++++++++++++++++++++++++--- 2 files changed, 198 insertions(+), 31 deletions(-) diff --git a/serde2/serde2_macros/src/lib.rs b/serde2/serde2_macros/src/lib.rs index c891e75c..03e33c05 100644 --- a/serde2/serde2_macros/src/lib.rs +++ b/serde2/serde2_macros/src/lib.rs @@ -1236,8 +1236,49 @@ fn deserialize_enum( fields: &[(Ident, Span, StaticFields)], state: P, enum_def: &EnumDef, - _generics: &ast::Generics, + generics: &ast::Generics, ) -> P { + let visitor_impl_generics = builder.from_generics(generics.clone()) + .add_ty_param_bound( + builder.path().global().ids(&["serde2", "de", "Deserialize"]).build() + ) + .build(); + + // Build `__Visitor(PhantomData, PhantomData, ...)` + let (visitor_struct, visitor_expr) = if generics.ty_params.is_empty() { + ( + builder.item().tuple_struct("__Visitor") + .build(), + builder.expr().id("__Visitor"), + ) + } else { + ( + builder.item().tuple_struct("__Visitor") + .generics().with(generics.clone()).build() + .with_tys( + generics.ty_params.iter().map(|ty_param| { + builder.ty().phantom_data().id(ty_param.ident) + }) + ) + .build(), + builder.expr().call().id("__Visitor") + .with_args( + generics.ty_params.iter().map(|_| { + builder.expr().phantom_data() + }) + ) + .build(), + ) + }; + + let visitor_ty = builder.ty().path() + .segment("__Visitor").with_generics(generics.clone()).build() + .build(); + + let value_ty = builder.ty().path() + .segment(type_ident).with_generics(generics.clone()).build() + .build(); + let type_name = builder.expr().str(type_ident); // Match arms to extract a variant from a string @@ -1253,6 +1294,10 @@ fn deserialize_enum( fields, cx.expr_ident(span, cx.ident_of("visitor")), variant_ptr, + &visitor_impl_generics, + &visitor_ty, + &visitor_expr, + &value_ty, ); let s = builder.expr().str(name); @@ -1261,15 +1306,15 @@ fn deserialize_enum( .collect(); quote_expr!(cx, { - struct __Visitor; + $visitor_struct; - impl ::serde2::de::Visitor for __Visitor { - type Value = $type_ident; + impl $visitor_impl_generics ::serde2::de::Visitor for $visitor_ty { + type Value = $value_ty; fn visit_enum<__V>(&mut self, name: &str, variant: &str, - mut visitor: __V) -> Result<$type_ident, __V::Error> + mut visitor: __V) -> Result<$value_ty, __V::Error> where __V: ::serde2::de::EnumVisitor, { if name == $type_name { @@ -1281,7 +1326,7 @@ fn deserialize_enum( fn visit_variant<__V>(&mut self, name: &str, - mut visitor: __V) -> Result<$type_ident, __V::Error> + mut visitor: __V) -> Result<$value_ty, __V::Error> where __V: ::serde2::de::EnumVisitor { match name { @@ -1291,7 +1336,7 @@ fn deserialize_enum( } } - $state.visit_enum(__Visitor) + $state.visit_enum($visitor_expr) }) } @@ -1304,6 +1349,10 @@ fn deserialize_enum_variant( fields: &StaticFields, state: P, variant_ptr: &P, + visitor_impl_generics: &ast::Generics, + visitor_ty: &P, + visitor_expr: &P, + value_ty: &P, ) -> P { let variant_path = cx.path(span, vec![type_ident, variant_ident]); @@ -1330,19 +1379,17 @@ fn deserialize_enum_variant( ); quote_expr!(cx, { - struct __Visitor; - - impl ::serde2::de::EnumSeqVisitor for __Visitor { - type Value = $type_ident; + impl $visitor_impl_generics ::serde2::de::EnumSeqVisitor for $visitor_ty { + type Value = $value_ty; fn visit< V: ::serde2::de::SeqVisitor, - >(&mut self, mut visitor: V) -> Result<$type_ident, V::Error> { + >(&mut self, mut visitor: V) -> Result<$value_ty, V::Error> { $visit_seq_expr } } - $state.visit_seq(__Visitor) + $state.visit_seq($visitor_expr) }) } } @@ -1379,19 +1426,17 @@ fn deserialize_enum_variant( quote_expr!(cx, { $field_deserializer - struct __Visitor; - - impl ::serde2::de::EnumMapVisitor for __Visitor { - type Value = $type_ident; + impl $visitor_impl_generics ::serde2::de::EnumMapVisitor for $visitor_ty { + type Value = $value_ty; fn visit< V: ::serde2::de::MapVisitor, - >(&mut self, mut visitor: V) -> Result<$type_ident, V::Error> { + >(&mut self, mut visitor: V) -> Result<$value_ty, V::Error> { $visit_map_expr } } - $state.visit_map(__Visitor) + $state.visit_map($visitor_expr) }) } } diff --git a/serde2/tests/test_macros.rs b/serde2/tests/test_macros.rs index 6c8770c1..2589e5f6 100644 --- a/serde2/tests/test_macros.rs +++ b/serde2/tests/test_macros.rs @@ -32,14 +32,13 @@ struct NamedUnit; #[derive(Debug, PartialEq)] #[derive_serialize] -//#[derive_deserialize] -enum Enum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a { +enum SerEnum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a { Unit, Seq( i8, B, &'a C, - //B::Type, + //C::Type, &'a mut D, //::Type, ), @@ -53,6 +52,28 @@ enum Enum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a { }, } +#[derive(Debug, PartialEq)] +#[derive_deserialize] +enum DeEnum /* where D: Trait */ { + Unit, + Seq( + i8, + B, + C, + //C::Type, + D, + //::Type, + ), + Map { + a: i8, + b: B, + c: C, + //d: C::Type, + e: D, + //f: ::Type, + }, +} + #[test] fn test_named_unit() { let named_unit = NamedUnit; @@ -183,14 +204,14 @@ fn test_de_named_map() { } #[test] -fn test_enum_unit() { +fn test_ser_enum_unit() { assert_eq!( - json::to_string(&Enum::Unit::).unwrap(), + json::to_string(&SerEnum::Unit::).unwrap(), "{\"Unit\":[]}" ); assert_eq!( - json::to_value(&Enum::Unit::), + json::to_value(&SerEnum::Unit::), Value::Object(btreemap!( "Unit".to_string() => Value::Array(vec![])) ) @@ -198,7 +219,7 @@ fn test_enum_unit() { } #[test] -fn test_enum_seq() { +fn test_ser_enum_seq() { let a = 1; let b = 2; let c = 3; @@ -207,7 +228,7 @@ fn test_enum_seq() { //let f = 6; assert_eq!( - json::to_string(&Enum::Seq( + json::to_string(&SerEnum::Seq( a, b, &c, @@ -219,7 +240,7 @@ fn test_enum_seq() { ); assert_eq!( - json::to_value(&Enum::Seq( + json::to_value(&SerEnum::Seq( a, b, &c, @@ -241,7 +262,7 @@ fn test_enum_seq() { } #[test] -fn test_enum_map() { +fn test_ser_enum_map() { let a = 1; let b = 2; let c = 3; @@ -250,7 +271,7 @@ fn test_enum_map() { //let f = 6; assert_eq!( - json::to_string(&Enum::Map { + json::to_string(&SerEnum::Map { a: a, b: b, c: &c, @@ -262,7 +283,7 @@ fn test_enum_map() { ); assert_eq!( - json::to_value(&Enum::Map { + json::to_value(&SerEnum::Map { a: a, b: b, c: &c, @@ -282,3 +303,104 @@ fn test_enum_map() { )) ); } + +#[test] +fn test_de_enum_unit() { + assert_eq!( + json::from_str("{\"Unit\":[]}").unwrap(), + DeEnum::Unit:: + ); + + assert_eq!( + json::from_value(Value::Object(btreemap!( + "Unit".to_string() => Value::Array(vec![])) + )).unwrap(), + DeEnum::Unit:: + ); +} + +#[test] +fn test_de_enum_seq() { + let a = 1; + let b = 2; + let c = 3; + //let d = 4; + let e = 5; + //let f = 6; + + assert_eq!( + json::from_str("{\"Seq\":[1,2,3,5]}").unwrap(), + DeEnum::Seq( + a, + b, + c, + //d, + e, + //f, + ) + ); + + assert_eq!( + json::from_value(Value::Object(btreemap!( + "Seq".to_string() => Value::Array(vec![ + Value::I64(1), + Value::I64(2), + Value::I64(3), + //Value::I64(4), + Value::I64(5), + //Value::I64(6), + ]) + ))).unwrap(), + DeEnum::Seq( + a, + b, + c, + //d, + e, + //e, + ) + ); +} + +#[test] +fn test_de_enum_map() { + let a = 1; + let b = 2; + let c = 3; + //let d = 4; + let e = 5; + //let f = 6; + + assert_eq!( + json::from_str("{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}").unwrap(), + DeEnum::Map { + a: a, + b: b, + c: c, + //d: d, + e: e, + //f: f, + } + ); + + assert_eq!( + json::from_value(Value::Object(btreemap!( + "Map".to_string() => Value::Object(btreemap![ + "a".to_string() => Value::I64(1), + "b".to_string() => Value::I64(2), + "c".to_string() => Value::I64(3), + //"d".to_string() => Value::I64(4) + "e".to_string() => Value::I64(5) + //"f".to_string() => Value::I64(6) + ]) + ))).unwrap(), + DeEnum::Map { + a: a, + b: b, + c: c, + //d: d, + e: e, + //f: f, + } + ); +}