mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-13 16:01:02 +00:00
Fix #[derive_serialize] for tuple structs
This commit is contained in:
+109
-22
@@ -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,
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
Reference in New Issue
Block a user