From fe64145c06109a6a0f693bd99f7a5fc5a0b254fe Mon Sep 17 00:00:00 2001 From: Erick Tryzelaar Date: Tue, 3 Mar 2015 21:14:43 -0800 Subject: [PATCH] Fix #[derive_serialize] for tuple structs --- serde2/serde2_macros/src/lib.rs | 131 ++++++++++++++++++++++++++------ serde2/tests/test_ser.rs | 52 +------------ 2 files changed, 111 insertions(+), 72 deletions(-) diff --git a/serde2/serde2_macros/src/lib.rs b/serde2/serde2_macros/src/lib.rs index 679b9333..d818cfec 100644 --- a/serde2/serde2_macros/src/lib.rs +++ b/serde2/serde2_macros/src/lib.rs @@ -126,18 +126,41 @@ fn serialize_substructure(cx: &ExtCtxt, match (&item.node, &*substr.fields) { (&ast::ItemStruct(ref struct_def, _), &Struct(ref fields)) => { - if fields.is_empty() { - serialize_tuple_struct(cx, - span, - visitor, - substr.type_ident) - } else { - serialize_struct(cx, - span, - visitor, - substr.type_ident, - fields, - struct_def) + let mut named_fields = vec![]; + let mut unnamed_fields = vec![]; + + for field in fields { + match field.name { + Some(name) => { named_fields.push((name, field.span)); } + None => { unnamed_fields.push(field.span); } + } + } + + match (named_fields.is_empty(), unnamed_fields.is_empty()) { + (true, true) => { + serialize_unit_struct(cx, + span, + visitor, + substr.type_ident) + } + (true, false) => { + serialize_tuple_struct(cx, + span, + visitor, + substr.type_ident, + &unnamed_fields) + } + (false, true) => { + serialize_struct(cx, + span, + visitor, + substr.type_ident, + &named_fields, + struct_def) + } + (false, false) => { + panic!("struct has named and unnamed fields") + } } } @@ -155,10 +178,10 @@ fn serialize_substructure(cx: &ExtCtxt, } } -fn serialize_tuple_struct(cx: &ExtCtxt, - span: Span, - visitor: P, - type_ident: Ident) -> P { +fn serialize_unit_struct(cx: &ExtCtxt, + span: Span, + visitor: P, + type_ident: Ident) -> P { let type_name = cx.expr_str( span, token::get_ident(type_ident)); @@ -166,11 +189,79 @@ fn serialize_tuple_struct(cx: &ExtCtxt, quote_expr!(cx, $visitor.visit_named_unit($type_name)) } +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)); + 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 i = i as u32; + + quote_arm!(cx, + $i => { + self.state += 1; + let v = try!(visitor.visit_seq_elt($first, &$expr)); + Ok(Some(v)) + } + ) + }) + .collect(); + + quote_expr!(cx, { + struct Visitor<'a> { + state: u32, + value: &'a $type_ident, + } + + impl<'a> ::serde2::ser::SeqVisitor for Visitor<'a> { + #[inline] + fn visit(&mut self, visitor: &mut V) -> Result, V::Error> + where V: ::serde2::ser::Visitor, + { + match self.state { + $arms + _ => Ok(None), + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = $len - (self.state as usize); + (size, Some(size)) + } + } + + $visitor.visit_named_seq($type_name, Visitor { + value: self, + state: 0, + }) + }) +} + + fn serialize_struct(cx: &ExtCtxt, span: Span, visitor: P, type_ident: Ident, - fields: &[FieldInfo], + fields: &[(Ident, Span)], struct_def: &StructDef) -> P { let type_name = cx.expr_str( span, @@ -184,14 +275,13 @@ fn serialize_struct(cx: &ExtCtxt, let arms: Vec = fields.iter() .zip(aliases.iter()) .enumerate() - .map(|(i, (&FieldInfo { name, span, .. }, alias_lit ))| { + .map(|(i, (&(name, span), alias_lit))| { let first = if i == 0 { quote_expr!(cx, true) } else { quote_expr!(cx, false) }; - let name = name.unwrap(); let expr = match alias_lit { &Some(lit) => { let lit = (*lit).clone(); @@ -243,9 +333,6 @@ fn serialize_struct(cx: &ExtCtxt, }) } - - - fn serialize_enum( cx: &ExtCtxt, span: Span, diff --git a/serde2/tests/test_ser.rs b/serde2/tests/test_ser.rs index 9aa66399..70102fbe 100644 --- a/serde2/tests/test_ser.rs +++ b/serde2/tests/test_ser.rs @@ -281,60 +281,12 @@ impl<'a> Visitor for AssertSerializer<'a> { } } +#[derive_serialize] struct NamedUnit; -impl Serialize for NamedUnit { - fn visit(&self, visitor: &mut V) -> Result - where V: Visitor, - { - visitor.visit_named_unit("NamedUnit") - } -} - +#[derive_serialize] struct NamedSeq(i32, i32, i32); -impl Serialize for NamedSeq { - fn visit(&self, visitor: &mut V) -> Result - where V: Visitor, - { - visitor.visit_named_seq("NamedSeq", NamedSeqVisitor { - tuple: self, - state: 0, - }) - } -} - -struct NamedSeqVisitor<'a> { - tuple: &'a NamedSeq, - state: u8, -} - -impl<'a> SeqVisitor for NamedSeqVisitor<'a> { - fn visit(&mut self, visitor: &mut V) -> Result, V::Error> - where V: Visitor, - { - match self.state { - 0 => { - self.state += 1; - Ok(Some(try!(visitor.visit_seq_elt(true, &self.tuple.0)))) - } - 1 => { - self.state += 1; - Ok(Some(try!(visitor.visit_seq_elt(false, &self.tuple.1)))) - } - 2 => { - self.state += 1; - Ok(Some(try!(visitor.visit_seq_elt(false, &self.tuple.2)))) - } - _ => Ok(None) - } - } - - fn size_hint(&self) -> (usize, Option) { - (3, Some(3)) - } -} - enum Enum { Unit, Seq(i32, i32),