From 124a306cd7bad7f315a36e3abb4a205b6aa5188f Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 6 Mar 2015 22:14:13 -0800 Subject: [PATCH] Fix #[derive_serialize] for generic structs --- serde2/serde2_macros/src/lib.rs | 51 ++++++++++++++++++++------------- serde2/tests/test_macros.rs | 34 ++++++++++++++++++++++ 2 files changed, 65 insertions(+), 20 deletions(-) diff --git a/serde2/serde2_macros/src/lib.rs b/serde2/serde2_macros/src/lib.rs index 0dff7c9b..23e2ec33 100644 --- a/serde2/serde2_macros/src/lib.rs +++ b/serde2/serde2_macros/src/lib.rs @@ -158,7 +158,8 @@ fn serialize_substructure(cx: &ExtCtxt, visitor, substr.type_ident, &named_fields, - struct_def) + struct_def, + generics) } (false, false) => { panic!("struct has named and unnamed fields") @@ -269,16 +270,17 @@ fn serialize_tuple_struct(cx: &ExtCtxt, }) } - fn serialize_struct(cx: &ExtCtxt, span: Span, visitor: P, type_ident: Ident, fields: &[(Ident, Span)], - struct_def: &StructDef) -> P { - let type_name = cx.expr_str( - span, - token::get_ident(type_ident)); + struct_def: &StructDef, + generics: &ast::Generics) -> P { + let ctx = builder::Ctx::new(); + let builder = builder::AstBuilder::new(&ctx).span(span); + + let type_name = builder.expr().str(type_ident); let len = fields.len(); let aliases : Vec> = struct_def.fields.iter() @@ -289,18 +291,11 @@ fn serialize_struct(cx: &ExtCtxt, .zip(aliases.iter()) .enumerate() .map(|(i, (&(name, span), alias_lit))| { - let first = if i == 0 { - quote_expr!(cx, true) - } else { - quote_expr!(cx, false) - }; + let first = builder.expr().bool(i == 0); - let expr = match alias_lit { - &Some(lit) => { - let lit = (*lit).clone(); - cx.expr_lit(lit.span, lit.node) - }, - &None => cx.expr_str(span, token::get_ident(name)), + let expr = match *alias_lit { + Some(lit) => builder.expr().build_lit(P(lit.clone())), + None => builder.expr().str(name), }; let i = i as u32; @@ -315,13 +310,29 @@ fn serialize_struct(cx: &ExtCtxt, }) .collect(); + let type_generics = builder.from_generics(generics.clone()) + .strip_bounds() + .build(); + + let visitor_impl_generics = builder.from_generics(generics.clone()) + .add_lifetime_bound("'__a") + .add_ty_param_bound( + builder.path().global().ids(&["serde2", "ser", "Serialize"]).build() + ) + .lifetime_name("'__a") + .build(); + + let visitor_generics = builder.from_generics(visitor_impl_generics.clone()) + .strip_bounds() + .build(); + quote_expr!(cx, { - struct Visitor<'a> { + struct Visitor $visitor_impl_generics { state: u32, - value: &'a $type_ident, + value: &'__a $type_ident $type_generics, } - impl<'a> ::serde2::ser::MapVisitor for Visitor<'a> { + impl $visitor_impl_generics ::serde2::ser::MapVisitor for Visitor $visitor_generics { #[inline] fn visit(&mut self, visitor: &mut V) -> Result, V::Error> where V: ::serde2::ser::Visitor, diff --git a/serde2/tests/test_macros.rs b/serde2/tests/test_macros.rs index 5e86cbaa..18d67642 100644 --- a/serde2/tests/test_macros.rs +++ b/serde2/tests/test_macros.rs @@ -33,6 +33,14 @@ struct NamedUnit; #[derive_serialize] struct NamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C); +#[derive(Debug, PartialEq)] +#[derive_serialize] +struct NamedMap<'a, 'b, A: 'a, B: 'b, C> { + a: &'a A, + b: &'b mut B, + c: C, +} + #[derive(Debug, PartialEq)] #[derive_serialize] //#[derive_deserialize] @@ -97,6 +105,32 @@ fn test_named_tuple() { ); } +#[test] +fn test_named_map() { + let a = 5; + let mut b = 6; + let c = 7; + let named_map = NamedMap { + a: &a, + b: &mut b, + c: c, + }; + + assert_eq!( + json::to_string(&named_map).unwrap(), + "{\"a\":5,\"b\":6,\"c\":7}" + ); + + assert_eq!( + json::to_value(&named_map), + Value::Object(btreemap![ + "a".to_string() => Value::I64(5), + "b".to_string() => Value::I64(6), + "c".to_string() => Value::I64(7) + ]) + ); +} + #[test] fn test_enum_unit() { assert_eq!(