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

View File

@ -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<Expr>,
type_ident: Ident) -> P<Expr> {
fn serialize_unit_struct(cx: &ExtCtxt,
span: Span,
visitor: P<Expr>,
type_ident: Ident) -> P<Expr> {
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<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,
span: Span,
visitor: P<Expr>,
type_ident: Ident,
fields: &[FieldInfo],
fields: &[(Ident, Span)],
struct_def: &StructDef) -> P<Expr> {
let type_name = cx.expr_str(
span,
@ -184,14 +275,13 @@ fn serialize_struct(cx: &ExtCtxt,
let arms: Vec<ast::Arm> = 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,

View File

@ -281,60 +281,12 @@ impl<'a> Visitor for AssertSerializer<'a> {
}
}
#[derive_serialize]
struct NamedUnit;
impl Serialize for NamedUnit {
fn visit<V>(&self, visitor: &mut V) -> Result<V::Value, V::Error>
where V: Visitor,
{
visitor.visit_named_unit("NamedUnit")
}
}
#[derive_serialize]
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 {
Unit,
Seq(i32, i32),