Fix #[derive_serialize] for tuple structs

This commit is contained in:
Erick Tryzelaar
2015-03-03 21:14:43 -08:00
parent 61fdcb0611
commit fe64145c06
2 changed files with 111 additions and 72 deletions
+109 -22
View File
@@ -126,18 +126,41 @@ fn serialize_substructure(cx: &ExtCtxt,
match (&item.node, &*substr.fields) { match (&item.node, &*substr.fields) {
(&ast::ItemStruct(ref struct_def, _), &Struct(ref fields)) => { (&ast::ItemStruct(ref struct_def, _), &Struct(ref fields)) => {
if fields.is_empty() { let mut named_fields = vec![];
serialize_tuple_struct(cx, let mut unnamed_fields = vec![];
span,
visitor, for field in fields {
substr.type_ident) match field.name {
} else { Some(name) => { named_fields.push((name, field.span)); }
serialize_struct(cx, None => { unnamed_fields.push(field.span); }
span, }
visitor, }
substr.type_ident,
fields, match (named_fields.is_empty(), unnamed_fields.is_empty()) {
struct_def) (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, fn serialize_unit_struct(cx: &ExtCtxt,
span: Span, span: Span,
visitor: P<Expr>, visitor: P<Expr>,
type_ident: Ident) -> P<Expr> { type_ident: Ident) -> P<Expr> {
let type_name = cx.expr_str( let type_name = cx.expr_str(
span, span,
token::get_ident(type_ident)); token::get_ident(type_ident));
@@ -166,11 +189,79 @@ fn serialize_tuple_struct(cx: &ExtCtxt,
quote_expr!(cx, $visitor.visit_named_unit($type_name)) quote_expr!(cx, $visitor.visit_named_unit($type_name))
} }
fn serialize_tuple_struct(cx: &ExtCtxt,
span: Span,
visitor: P<Expr>,
type_ident: Ident,
fields: &[Span]) -> P<Expr> {
let type_name = cx.expr_str(
span,
token::get_ident(type_ident));
let len = fields.len();
let arms: Vec<ast::Arm> = 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<V>(&mut self, visitor: &mut V) -> Result<Option<V::Value>, V::Error>
where V: ::serde2::ser::Visitor,
{
match self.state {
$arms
_ => Ok(None),
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
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, fn serialize_struct(cx: &ExtCtxt,
span: Span, span: Span,
visitor: P<Expr>, visitor: P<Expr>,
type_ident: Ident, type_ident: Ident,
fields: &[FieldInfo], fields: &[(Ident, Span)],
struct_def: &StructDef) -> P<Expr> { struct_def: &StructDef) -> P<Expr> {
let type_name = cx.expr_str( let type_name = cx.expr_str(
span, span,
@@ -184,14 +275,13 @@ fn serialize_struct(cx: &ExtCtxt,
let arms: Vec<ast::Arm> = fields.iter() let arms: Vec<ast::Arm> = fields.iter()
.zip(aliases.iter()) .zip(aliases.iter())
.enumerate() .enumerate()
.map(|(i, (&FieldInfo { name, span, .. }, alias_lit ))| { .map(|(i, (&(name, span), alias_lit))| {
let first = if i == 0 { let first = if i == 0 {
quote_expr!(cx, true) quote_expr!(cx, true)
} else { } else {
quote_expr!(cx, false) quote_expr!(cx, false)
}; };
let name = name.unwrap();
let expr = match alias_lit { let expr = match alias_lit {
&Some(lit) => { &Some(lit) => {
let lit = (*lit).clone(); let lit = (*lit).clone();
@@ -243,9 +333,6 @@ fn serialize_struct(cx: &ExtCtxt,
}) })
} }
fn serialize_enum( fn serialize_enum(
cx: &ExtCtxt, cx: &ExtCtxt,
span: Span, span: Span,
+2 -50
View File
@@ -281,60 +281,12 @@ impl<'a> Visitor for AssertSerializer<'a> {
} }
} }
#[derive_serialize]
struct NamedUnit; struct NamedUnit;
impl Serialize for NamedUnit { #[derive_serialize]
fn visit<V>(&self, visitor: &mut V) -> Result<V::Value, V::Error>
where V: Visitor,
{
visitor.visit_named_unit("NamedUnit")
}
}
struct NamedSeq(i32, i32, i32); struct NamedSeq(i32, i32, i32);
impl Serialize for NamedSeq {
fn visit<V>(&self, visitor: &mut V) -> Result<V::Value, V::Error>
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<V>(&mut self, visitor: &mut V) -> Result<Option<V::Value>, 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<usize>) {
(3, Some(3))
}
}
enum Enum { enum Enum {
Unit, Unit,
Seq(i32, i32), Seq(i32, i32),