mirror of
https://github.com/pezkuwichain/serde.git
synced 2026-06-15 19:01:01 +00:00
Merge #[derive_serialize] for structs and struct variants
This commit is contained in:
+129
-163
@@ -133,7 +133,7 @@ fn serialize_substructure(
|
|||||||
|
|
||||||
for field in fields {
|
for field in fields {
|
||||||
match field.name {
|
match field.name {
|
||||||
Some(name) => { named_fields.push((name, field.span)); }
|
Some(name) => { named_fields.push(name); }
|
||||||
None => { unnamed_fields += 1; }
|
None => { unnamed_fields += 1; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,42 +310,92 @@ fn serialize_struct(
|
|||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
serializer: P<Expr>,
|
serializer: P<Expr>,
|
||||||
type_ident: Ident,
|
type_ident: Ident,
|
||||||
fields: &[(Ident, Span)],
|
fields: &[Ident],
|
||||||
struct_def: &StructDef,
|
struct_def: &StructDef,
|
||||||
generics: &ast::Generics
|
generics: &ast::Generics
|
||||||
) -> P<Expr> {
|
) -> P<Expr> {
|
||||||
|
let value_ty = builder.ty()
|
||||||
|
.ref_()
|
||||||
|
.lifetime("'__a")
|
||||||
|
.ty().path()
|
||||||
|
.segment(type_ident).with_generics(generics.clone()).build()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||||
|
cx,
|
||||||
|
builder,
|
||||||
|
value_ty,
|
||||||
|
struct_def,
|
||||||
|
generics,
|
||||||
|
fields.iter().map(|field| quote_expr!(cx, &self.value.$field)),
|
||||||
|
);
|
||||||
|
|
||||||
let type_name = builder.expr().str(type_ident);
|
let type_name = builder.expr().str(type_ident);
|
||||||
let len = fields.len();
|
|
||||||
|
|
||||||
let aliases : Vec<Option<&ast::Lit>> = struct_def.fields.iter()
|
quote_expr!(cx, {
|
||||||
.map(field_alias)
|
$visitor_struct
|
||||||
.collect();
|
$visitor_impl
|
||||||
|
$serializer.visit_named_map($type_name, Visitor {
|
||||||
|
value: self,
|
||||||
|
state: 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
let arms: Vec<ast::Arm> = fields.iter()
|
fn serialize_struct_visitor<I>(
|
||||||
.zip(aliases.iter())
|
cx: &ExtCtxt,
|
||||||
.enumerate()
|
builder: &aster::AstBuilder,
|
||||||
.map(|(i, (&(name, _), alias_lit))| {
|
value_ty: P<ast::Ty>,
|
||||||
let first = builder.expr().bool(i == 0);
|
struct_def: &StructDef,
|
||||||
|
generics: &ast::Generics,
|
||||||
|
value_exprs: I,
|
||||||
|
) -> (P<ast::Item>, P<ast::Item>)
|
||||||
|
where I: Iterator<Item=P<ast::Expr>>,
|
||||||
|
{
|
||||||
|
let len = struct_def.fields.len();
|
||||||
|
|
||||||
let expr = match *alias_lit {
|
let key_exprs = struct_def.fields.iter()
|
||||||
|
.map(|field| {
|
||||||
|
match field_alias(field) {
|
||||||
Some(lit) => builder.expr().build_lit(P(lit.clone())),
|
Some(lit) => builder.expr().build_lit(P(lit.clone())),
|
||||||
None => builder.expr().str(name),
|
None => {
|
||||||
};
|
match field.node.kind {
|
||||||
|
ast::NamedField(name, _) => {
|
||||||
|
builder.expr().str(name)
|
||||||
|
}
|
||||||
|
ast::UnnamedField(_) => {
|
||||||
|
cx.bug("struct has named and unnamed fields")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let arms: Vec<ast::Arm> = key_exprs
|
||||||
|
.zip(value_exprs)
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, (key_expr, value_expr))| {
|
||||||
|
let first = i == 0;
|
||||||
|
|
||||||
quote_arm!(cx,
|
quote_arm!(cx,
|
||||||
$i => {
|
$i => {
|
||||||
self.state += 1;
|
self.state += 1;
|
||||||
let v = try!(serializer.visit_map_elt($first, $expr, &self.value.$name));
|
Ok(
|
||||||
Ok(Some(v))
|
Some(
|
||||||
|
try!(
|
||||||
|
serializer.visit_map_elt(
|
||||||
|
$first,
|
||||||
|
$key_expr,
|
||||||
|
$value_expr,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let type_generics = builder.from_generics(generics.clone())
|
|
||||||
.strip_bounds()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let visitor_impl_generics = builder.from_generics(generics.clone())
|
let visitor_impl_generics = builder.from_generics(generics.clone())
|
||||||
.add_lifetime_bound("'__a")
|
.add_lifetime_bound("'__a")
|
||||||
.add_ty_param_bound(
|
.add_ty_param_bound(
|
||||||
@@ -354,38 +404,42 @@ fn serialize_struct(
|
|||||||
.lifetime_name("'__a")
|
.lifetime_name("'__a")
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
let where_clause = &visitor_impl_generics.where_clause;
|
||||||
|
|
||||||
let visitor_generics = builder.from_generics(visitor_impl_generics.clone())
|
let visitor_generics = builder.from_generics(visitor_impl_generics.clone())
|
||||||
.strip_bounds()
|
.strip_bounds()
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
quote_expr!(cx, {
|
(
|
||||||
struct Visitor $visitor_impl_generics {
|
quote_item!(cx,
|
||||||
state: usize,
|
struct Visitor $visitor_impl_generics $where_clause {
|
||||||
value: &'__a $type_ident $type_generics,
|
state: usize,
|
||||||
}
|
value: $value_ty,
|
||||||
|
}
|
||||||
|
).unwrap(),
|
||||||
|
|
||||||
impl $visitor_impl_generics ::serde::ser::MapVisitor for Visitor $visitor_generics {
|
quote_item!(cx,
|
||||||
#[inline]
|
impl $visitor_impl_generics
|
||||||
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
|
::serde::ser::MapVisitor
|
||||||
where S: ::serde::ser::Serializer,
|
for Visitor $visitor_generics
|
||||||
{
|
$where_clause {
|
||||||
match self.state {
|
#[inline]
|
||||||
$arms
|
fn visit<S>(&mut self, serializer: &mut S) -> Result<Option<()>, S::Error>
|
||||||
_ => Ok(None),
|
where S: ::serde::ser::Serializer,
|
||||||
|
{
|
||||||
|
match self.state {
|
||||||
|
$arms
|
||||||
|
_ => Ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn len(&self) -> Option<usize> {
|
||||||
|
Some($len)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
).unwrap(),
|
||||||
#[inline]
|
)
|
||||||
fn len(&self) -> Option<usize> {
|
|
||||||
Some($len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$serializer.visit_named_map($type_name, Visitor {
|
|
||||||
value: self,
|
|
||||||
state: 0,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_enum(
|
fn serialize_enum(
|
||||||
@@ -421,7 +475,7 @@ fn serialize_enum(
|
|||||||
fields,
|
fields,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ast::StructVariantKind(_) => {
|
ast::StructVariantKind(ref struct_def) => {
|
||||||
serialize_struct_variant(
|
serialize_struct_variant(
|
||||||
cx,
|
cx,
|
||||||
builder,
|
builder,
|
||||||
@@ -429,7 +483,7 @@ fn serialize_enum(
|
|||||||
type_name,
|
type_name,
|
||||||
variant_name,
|
variant_name,
|
||||||
generics,
|
generics,
|
||||||
variant,
|
struct_def,
|
||||||
fields,
|
fields,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -489,57 +543,22 @@ fn serialize_tuple_variant(
|
|||||||
fn serialize_struct_variant(
|
fn serialize_struct_variant(
|
||||||
cx: &ExtCtxt,
|
cx: &ExtCtxt,
|
||||||
builder: &aster::AstBuilder,
|
builder: &aster::AstBuilder,
|
||||||
serializer: P<ast::Expr>,
|
serializer: P<Expr>,
|
||||||
type_name: P<ast::Expr>,
|
type_name: P<ast::Expr>,
|
||||||
variant_name: P<ast::Expr>,
|
variant_name: P<ast::Expr>,
|
||||||
generics: &ast::Generics,
|
generics: &ast::Generics,
|
||||||
variant: &ast::Variant,
|
struct_def: &ast::StructDef,
|
||||||
fields: &[FieldInfo],
|
fields: &[FieldInfo],
|
||||||
) -> P<Expr> {
|
) -> P<Expr> {
|
||||||
let trait_generics = builder.from_generics(generics.clone())
|
let value_ty = builder.ty().tuple()
|
||||||
.add_lifetime_bound("'__a")
|
.with_tys(
|
||||||
.add_ty_param_bound(
|
struct_def.fields.iter().map(|field| {
|
||||||
builder.path().global().ids(&["serde", "ser", "Serialize"]).build()
|
builder.ty()
|
||||||
|
.ref_()
|
||||||
|
.lifetime("'__a")
|
||||||
|
.build_ty(field.node.ty.clone())
|
||||||
|
})
|
||||||
)
|
)
|
||||||
.lifetime_name("'__a")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let where_clause = &generics.where_clause;
|
|
||||||
|
|
||||||
let type_generics = builder.from_generics(trait_generics.clone())
|
|
||||||
.strip_bounds()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
let (trait_name, method, tys,): (_, _, Vec<_>) = match variant.node.kind {
|
|
||||||
ast::TupleVariantKind(ref args) => {
|
|
||||||
(
|
|
||||||
cx.ident_of("SeqVisitor"),
|
|
||||||
cx.ident_of("visit_enum_seq"),
|
|
||||||
args.iter()
|
|
||||||
.map(|arg| arg.ty.clone())
|
|
||||||
.collect()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
ast::StructVariantKind(ref struct_def) => {
|
|
||||||
(
|
|
||||||
cx.ident_of("MapVisitor"),
|
|
||||||
cx.ident_of("visit_enum_map"),
|
|
||||||
struct_def.fields.iter()
|
|
||||||
.map(|field| field.node.ty.clone())
|
|
||||||
.collect()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let value_ty = builder.ty()
|
|
||||||
.tuple()
|
|
||||||
.with_tys(tys.into_iter().map(|ty| {
|
|
||||||
builder.ty()
|
|
||||||
.ref_()
|
|
||||||
.lifetime("'__a")
|
|
||||||
.build_ty(ty)
|
|
||||||
}))
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let value_expr = builder.expr().tuple()
|
let value_expr = builder.expr().tuple()
|
||||||
@@ -552,79 +571,26 @@ fn serialize_struct_variant(
|
|||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
let visitor_arms: Vec<ast::Arm> = fields.iter()
|
let (visitor_struct, visitor_impl) = serialize_struct_visitor(
|
||||||
.enumerate()
|
cx,
|
||||||
.map(|(state, field)| {
|
builder,
|
||||||
let first = state == 0;
|
value_ty,
|
||||||
|
struct_def,
|
||||||
let field_expr = builder.expr()
|
generics,
|
||||||
.tup_field(state)
|
(0 .. fields.len()).map(|i| {
|
||||||
.field("value").self_();
|
builder.expr()
|
||||||
|
.tup_field(i)
|
||||||
let visit_expr = match field.name {
|
.field("value").self_()
|
||||||
Some(real_name) => {
|
|
||||||
let real_name = builder.expr().str(real_name);
|
|
||||||
|
|
||||||
quote_expr!(cx,
|
|
||||||
::serde::ser::Serializer::visit_map_elt(
|
|
||||||
serializer,
|
|
||||||
$first,
|
|
||||||
$real_name,
|
|
||||||
$field_expr,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
quote_expr!(cx,
|
|
||||||
::serde::ser::Serializer::visit_seq_elt(
|
|
||||||
serializer,
|
|
||||||
$first,
|
|
||||||
$field_expr,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
quote_arm!(cx,
|
|
||||||
$state => {
|
|
||||||
self.state += 1;
|
|
||||||
Ok(Some(try!($visit_expr)))
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.collect();
|
);
|
||||||
|
|
||||||
let len = fields.len();
|
|
||||||
|
|
||||||
quote_expr!(cx, {
|
quote_expr!(cx, {
|
||||||
struct __Visitor $trait_generics $where_clause {
|
$visitor_struct
|
||||||
state: usize,
|
$visitor_impl
|
||||||
value: $value_ty,
|
$serializer.visit_enum_map($type_name, $variant_name, Visitor {
|
||||||
}
|
value: $value_expr,
|
||||||
|
state: 0,
|
||||||
impl $trait_generics ::serde::ser::$trait_name for __Visitor $type_generics $where_clause {
|
})
|
||||||
fn visit<V>(&mut self, serializer: &mut V) -> Result<Option<()>, V::Error>
|
|
||||||
where V: ::serde::ser::Serializer,
|
|
||||||
{
|
|
||||||
match self.state {
|
|
||||||
$visitor_arms
|
|
||||||
_ => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn len(&self) -> Option<usize> {
|
|
||||||
Some($len)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
::serde::ser::Serializer::$method(
|
|
||||||
$serializer,
|
|
||||||
$type_name,
|
|
||||||
$variant_name,
|
|
||||||
__Visitor {
|
|
||||||
state: 0,
|
|
||||||
value: $value_expr,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1126,7 +1092,7 @@ fn declare_map_field_devisitor(
|
|||||||
ast::EnumDef { variants: field_variants });
|
ast::EnumDef { variants: field_variants });
|
||||||
|
|
||||||
// Get aliases
|
// Get aliases
|
||||||
let aliases : Vec<Option<&ast::Lit>> = struct_def.fields.iter()
|
let aliases: Vec<Option<&ast::Lit>> = struct_def.fields.iter()
|
||||||
.map(field_alias)
|
.map(field_alias)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user