From a565df9cf7f7da9bdaf76edfed7f45eb4f148e56 Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Fri, 6 Mar 2015 19:11:47 -0800 Subject: [PATCH] Fix #[derive_serialize] for tuple structs --- serde2/Cargo.toml | 2 +- serde2/serde2_macros/src/lib.rs | 56 ++++++---- serde2/src/ser.rs | 9 ++ serde2/tests/test_macros.rs | 182 ++++++++++++++++++++++++++++++-- 4 files changed, 215 insertions(+), 34 deletions(-) diff --git a/serde2/Cargo.toml b/serde2/Cargo.toml index d72444a8..f7fbd826 100644 --- a/serde2/Cargo.toml +++ b/serde2/Cargo.toml @@ -9,5 +9,5 @@ name = "serde2" [dependencies] rustc-serialize = "*" -[dependencies.serde2_macros] +[dev-dependencies.serde2_macros] path = "serde2_macros/" diff --git a/serde2/serde2_macros/src/lib.rs b/serde2/serde2_macros/src/lib.rs index e02d03f2..0dff7c9b 100644 --- a/serde2/serde2_macros/src/lib.rs +++ b/serde2/serde2_macros/src/lib.rs @@ -126,7 +126,7 @@ fn serialize_substructure(cx: &ExtCtxt, let visitor = substr.nonself_args[0].clone(); match (&item.node, &*substr.fields) { - (&ast::ItemStruct(ref struct_def, _), &Struct(ref fields)) => { + (&ast::ItemStruct(ref struct_def, ref generics), &Struct(ref fields)) => { let mut named_fields = vec![]; let mut unnamed_fields = vec![]; @@ -149,7 +149,8 @@ fn serialize_substructure(cx: &ExtCtxt, span, visitor, substr.type_ident, - &unnamed_fields) + &unnamed_fields, + generics) } (false, true) => { serialize_struct(cx, @@ -194,25 +195,20 @@ fn serialize_tuple_struct(cx: &ExtCtxt, span: Span, visitor: P, type_ident: Ident, - fields: &[Span]) -> P { - let type_name = cx.expr_str( - span, - token::get_ident(type_ident)); + fields: &[Span], + 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 arms: Vec = fields.iter() - .enumerate() - .map(|(i, span)| { - let first = if i == 0 { - quote_expr!(cx, true) - } else { - quote_expr!(cx, false) - }; - - let expr = cx.expr_tup_field_access( - *span, - quote_expr!(cx, self.value), - i); + let arms: Vec = (0 .. fields.len()) + .map(|i| { + let first = builder.expr().bool(i == 0); + let expr = builder.expr() + .tup_field(i) + .field("value").self_(); let i = i as u32; @@ -226,13 +222,29 @@ fn serialize_tuple_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::SeqVisitor for Visitor<'a> { + impl $visitor_impl_generics ::serde2::ser::SeqVisitor for Visitor $visitor_generics { #[inline] fn visit(&mut self, visitor: &mut V) -> Result, V::Error> where V: ::serde2::ser::Visitor, diff --git a/serde2/src/ser.rs b/serde2/src/ser.rs index a639bd32..2efb786a 100644 --- a/serde2/src/ser.rs +++ b/serde2/src/ser.rs @@ -605,6 +605,15 @@ impl<'a, T> Serialize for &'a T where T: Serialize { } } +impl<'a, T> Serialize for &'a mut T where T: Serialize { + #[inline] + fn visit(&self, visitor: &mut V) -> Result + where V: Visitor, + { + (**self).visit(visitor) + } +} + impl Serialize for Box where T: Serialize { #[inline] fn visit(&self, visitor: &mut V) -> Result diff --git a/serde2/tests/test_macros.rs b/serde2/tests/test_macros.rs index c58c4d1b..5e86cbaa 100644 --- a/serde2/tests/test_macros.rs +++ b/serde2/tests/test_macros.rs @@ -3,37 +3,197 @@ extern crate serde2; +use std::collections::BTreeMap; +use serde2::json::{self, Value}; + +macro_rules! btreemap { + () => { + BTreeMap::new() + }; + ($($key:expr => $value:expr),+) => { + { + let mut map = BTreeMap::new(); + $(map.insert($key, $value);)+ + map + } + } +} + /* trait Trait { type Type; } */ +#[derive(Debug, PartialEq)] #[derive_serialize] struct NamedUnit; +#[derive(Debug, PartialEq)] +#[derive_serialize] +struct NamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C); + +#[derive(Debug, PartialEq)] #[derive_serialize] //#[derive_deserialize] -enum Enum<'a, A: 'a, B: /* Trait + */ 'a, C> where C: /* Trait + */ 'a { +enum Enum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a { Unit, Seq( i8, - &'a A, - &'a B, - //B::Type, + B, &'a C, - //::Type, + //B::Type, + &'a mut D, + //::Type, ), Map { a: i8, - b: &'a A, - c: &'a B, - //d: B::Type, - e: &'a C, - //f: ::Type, + b: B, + c: &'a C, + //d: C::Type, + e: &'a mut D, + //f: ::Type, }, } #[test] -fn test() { +fn test_named_unit() { + let named_unit = NamedUnit; + + assert_eq!( + json::to_string(&named_unit).unwrap(), + "null".to_string() + ); + + assert_eq!( + json::to_value(&named_unit), + Value::Null + ); + + /* + let v = json::from_str("null").unwrap(); + assert_eq!(v, named_unit); + + let v = json::from_value(Value::Null).unwrap(); + assert_eq!(v, named_unit); + */ +} + +#[test] +fn test_named_tuple() { + let a = 5; + let mut b = 6; + let c = 7; + let named_tuple = NamedTuple(&a, &mut b, c); + + assert_eq!( + json::to_string(&named_tuple).unwrap(), + "[5,6,7]" + ); + + assert_eq!( + json::to_value(&named_tuple), + Value::Array(vec![Value::I64(5), Value::I64(6), Value::I64(7)]) + ); +} + +#[test] +fn test_enum_unit() { + assert_eq!( + json::to_string(&Enum::Unit::).unwrap(), + "{\"Unit\":[]}" + ); + + assert_eq!( + json::to_value(&Enum::Unit::), + Value::Object(btreemap!( + "Unit".to_string() => Value::Array(vec![])) + ) + ); +} + +#[test] +fn test_enum_seq() { + let a = 1; + let b = 2; + let c = 3; + //let d = 4; + let mut e = 5; + //let f = 6; + + assert_eq!( + json::to_string(&Enum::Seq( + a, + b, + &c, + //d, + &mut e, + //f, + )).unwrap(), + "{\"Seq\":[1,2,3,5]}".to_string() + ); + + assert_eq!( + json::to_value(&Enum::Seq( + a, + b, + &c, + //d, + &mut e, + //e, + )), + 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), + ]) + )) + ); +} + +#[test] +fn test_enum_map() { + let a = 1; + let b = 2; + let c = 3; + //let d = 4; + let mut e = 5; + //let f = 6; + + assert_eq!( + json::to_string(&Enum::Map { + a: a, + b: b, + c: &c, + //d: d, + e: &mut e, + //f: f, + }).unwrap(), + "{\"Map\":{\"a\":1,\"b\":2,\"c\":3,\"e\":5}}".to_string() + ); + + assert_eq!( + json::to_value(&Enum::Map { + a: a, + b: b, + c: &c, + //d: d, + e: &mut e, + //f: f, + }), + 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) + ]) + )) + ); }