Get rid of syntax::ext::generic from #[derive_deserialize]

This commit is contained in:
Erick Tryzelaar
2015-03-15 17:47:25 -07:00
parent b9f5d22630
commit 9fc9d1b33a
3 changed files with 303 additions and 405 deletions
+261 -361
View File
@@ -3,31 +3,13 @@ use syntax::ast::{
MetaItem, MetaItem,
Item, Item,
Expr, Expr,
MutMutable,
StructDef, StructDef,
EnumDef, EnumDef,
}; };
use syntax::ast; use syntax::ast;
use syntax::codemap::Span; use syntax::codemap::Span;
use syntax::ext::base::{ExtCtxt, ItemDecorator}; use syntax::ext::base::ExtCtxt;
use syntax::ext::build::AstBuilder; use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic::{
MethodDef,
Named,
StaticFields,
StaticStruct,
StaticEnum,
Substructure,
TraitDef,
Unnamed,
combine_substructure,
};
use syntax::ext::deriving::generic::ty::{
Borrowed,
LifetimeBounds,
Ty,
Path,
};
use syntax::parse::token; use syntax::parse::token;
use syntax::ptr::P; use syntax::ptr::P;
@@ -37,148 +19,148 @@ use field;
pub fn expand_derive_deserialize( pub fn expand_derive_deserialize(
cx: &mut ExtCtxt, cx: &mut ExtCtxt,
sp: Span, span: Span,
mitem: &MetaItem, _mitem: &MetaItem,
item: &Item, item: &Item,
push: &mut FnMut(P<ast::Item>) push: &mut FnMut(P<ast::Item>)
) { ) {
let inline = cx.meta_word(sp, token::InternedString::new("inline"));
let attrs = vec!(cx.attribute(sp, inline));
let trait_def = TraitDef {
span: sp,
attributes: Vec::new(),
path: Path::new(vec!["serde", "de", "Deserialize"]),
additional_bounds: Vec::new(),
generics: LifetimeBounds::empty(),
associated_types: vec![],
methods: vec!(
MethodDef {
name: "deserialize",
generics: LifetimeBounds {
lifetimes: Vec::new(),
bounds: vec![
("__D", vec![Path::new(vec!["serde", "de", "Deserializer"])]),
],
},
explicit_self: None,
args: vec![
Ty::Ptr(
Box::new(Ty::Literal(Path::new_local("__D"))),
Borrowed(None, MutMutable)
),
],
ret_ty: Ty::Literal(
Path::new_(
vec!["std", "result", "Result"],
None,
vec![
Box::new(Ty::Self_),
Box::new(Ty::Literal(Path::new_(vec!["__D", "Error"],
None,
vec![],
false))),
],
true
)
),
attributes: attrs,
combine_substructure: combine_substructure(Box::new(|a, b, c| {
deserialize_substructure(a, b, c, item)
})),
})
};
trait_def.expand(cx, mitem, item, |item| push(item))
}
fn deserialize_substructure(
cx: &ExtCtxt,
span: Span,
substr: &Substructure,
item: &Item,
) -> P<Expr> {
let builder = aster::AstBuilder::new().span(span); let builder = aster::AstBuilder::new().span(span);
let state = substr.nonself_args[0].clone();
let generics = match item.node { let generics = match item.node {
ast::ItemStruct(_, ref generics) => generics, ast::ItemStruct(_, ref generics) => generics,
ast::ItemEnum(_, ref generics) => generics, ast::ItemEnum(_, ref generics) => generics,
_ => cx.bug("expected ItemStruct or ItemEnum in derive(Deserialize)") _ => cx.bug("expected ItemStruct or ItemEnum in #[derive_deserialize]")
}; };
let trait_generics = builder.from_generics(generics.clone()) let impl_generics = builder.from_generics(generics.clone())
.add_ty_param_bound( .add_ty_param_bound(
builder.path().global().ids(&["serde", "de", "Deserialize"]).build() builder.path().global().ids(&["serde", "de", "Deserialize"]).build()
) )
.build(); .build();
let type_generics = builder.from_generics(trait_generics.clone()) let ty = builder.ty().path()
.strip_bounds() .segment(item.ident).with_generics(impl_generics.clone()).build()
.build(); .build();
let visitor_ty = builder.ty().path() let body = deserialize_body(
.segment("__Visitor").with_generics(trait_generics.clone()).build() cx,
.build();
// Build `__Visitor<A, B, ...>(PhantomData<A>, PhantomData<B>, ...)`
let (visitor_item, visitor_expr) = deserialize_visitor(
&builder, &builder,
&trait_generics item,
&impl_generics,
ty.clone(),
); );
let value_ty = builder.ty().path() let where_clause = &impl_generics.where_clause;
.segment(substr.type_ident).with_generics(trait_generics.clone()).build()
.build();
match *substr.fields { let impl_item = quote_item!(cx,
StaticStruct(ref struct_def, ref fields) => { #[automatically_derived]
impl $impl_generics ::serde::de::Deserialize for $ty $where_clause {
fn deserialize<__D>(deserializer: &mut __D) -> Result<$ty, __D::Error>
where __D: ::serde::de::Deserializer,
{
$body
}
}
).unwrap();
push(impl_item)
}
fn deserialize_body(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
item: &Item,
impl_generics: &ast::Generics,
ty: P<ast::Ty>,
) -> P<ast::Expr> {
match item.node {
ast::ItemStruct(ref struct_def, _) => {
deserialize_item_struct(
cx,
builder,
item,
impl_generics,
ty,
struct_def,
)
}
ast::ItemEnum(ref enum_def, _) => {
deserialize_item_enum(
cx,
builder,
item.ident,
impl_generics,
ty,
enum_def,
)
}
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive_deserialize]")
}
}
fn deserialize_item_struct(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
item: &Item,
impl_generics: &ast::Generics,
ty: P<ast::Ty>,
struct_def: &ast::StructDef,
) -> P<ast::Expr> {
let mut named_fields = vec![];
let mut unnamed_fields = 0;
for field in struct_def.fields.iter() {
match field.node.kind {
ast::NamedField(name, _) => { named_fields.push(name); }
ast::UnnamedField(_) => { unnamed_fields += 1; }
}
}
match (named_fields.is_empty(), unnamed_fields == 0) {
(true, true) => {
deserialize_unit_struct(
cx,
&builder,
item.ident,
)
}
(true, false) => {
deserialize_tuple_struct(
cx,
&builder,
item.ident,
impl_generics,
ty,
unnamed_fields,
)
}
(false, true) => {
deserialize_struct( deserialize_struct(
cx, cx,
&builder, &builder,
substr.type_ident, item.ident,
substr.type_ident, impl_generics,
builder.path().id(substr.type_ident).build(), ty,
fields,
state,
struct_def, struct_def,
&trait_generics, named_fields,
visitor_item,
visitor_ty,
visitor_expr,
value_ty,
) )
} }
StaticEnum(ref enum_def, ref fields) => { (false, false) => {
deserialize_enum( cx.bug("struct has named and unnamed fields")
cx,
&builder,
substr.type_ident,
&fields,
state,
enum_def,
&trait_generics,
&type_generics,
visitor_item,
visitor_ty,
visitor_expr,
value_ty,
)
} }
_ => cx.bug("expected StaticEnum or StaticStruct in derive(Deserialize)")
} }
} }
// Build `__Visitor<A, B, ...>(PhantomData<A>, PhantomData<B>, ...)` // Build `__Visitor<A, B, ...>(PhantomData<A>, PhantomData<B>, ...)`
fn deserialize_visitor( fn deserialize_visitor(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
trait_generics: &ast::Generics, trait_generics: &ast::Generics,
) -> (P<ast::Item>, P<ast::Expr>) { ) -> (P<ast::Item>, P<ast::Ty>, P<ast::Expr>) {
if trait_generics.ty_params.is_empty() { if trait_generics.ty_params.is_empty() {
( (
builder.item().tuple_struct("__Visitor") builder.item().tuple_struct("__Visitor").build(),
.build(), builder.ty().id("__Visitor"),
builder.expr().id("__Visitor"), builder.expr().id("__Visitor"),
) )
} else { } else {
@@ -191,6 +173,9 @@ fn deserialize_visitor(
}) })
) )
.build(), .build(),
builder.ty().path()
.segment("__Visitor").with_generics(trait_generics.clone()).build()
.build(),
builder.expr().call().id("__Visitor") builder.expr().call().id("__Visitor")
.with_args( .with_args(
trait_generics.ty_params.iter().map(|_| { trait_generics.ty_params.iter().map(|_| {
@@ -202,80 +187,12 @@ fn deserialize_visitor(
} }
} }
fn deserialize_struct(
cx: &ExtCtxt,
builder: &aster::AstBuilder,
type_ident: Ident,
struct_ident: Ident,
struct_path: ast::Path,
fields: &StaticFields,
state: P<ast::Expr>,
struct_def: &StructDef,
trait_generics: &ast::Generics,
visitor_item: P<ast::Item>,
visitor_ty: P<ast::Ty>,
visitor_expr: P<ast::Expr>,
value_ty: P<ast::Ty>,
) -> P<ast::Expr> {
match *fields {
Unnamed(ref fields) if fields.is_empty() => {
deserialize_unit_struct(
cx,
builder,
type_ident,
struct_ident,
struct_path,
state,
)
}
Unnamed(ref fields) => {
deserialize_tuple_struct(
cx,
builder,
struct_ident,
struct_path,
&fields,
state,
trait_generics,
visitor_item,
visitor_ty,
visitor_expr,
value_ty,
)
}
Named(ref fields) => {
let fields: Vec<_> = fields.iter()
.map(|&(name, _)| name.clone())
.collect();
deserialize_struct_named_fields(
cx,
builder,
struct_ident,
struct_path,
&fields,
state,
struct_def,
trait_generics,
visitor_item,
visitor_ty,
visitor_expr,
value_ty,
)
}
}
}
fn deserialize_unit_struct( fn deserialize_unit_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
struct_ident: Ident,
struct_path: ast::Path,
state: P<ast::Expr>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let struct_name = builder.expr().str(struct_ident); let type_name = builder.expr().str(type_ident);
let result = builder.expr().build_path(struct_path);
quote_expr!(cx, { quote_expr!(cx, {
struct __Visitor; struct __Visitor;
@@ -287,14 +204,14 @@ fn deserialize_unit_struct(
fn visit_unit<E>(&mut self) -> Result<$type_ident, E> fn visit_unit<E>(&mut self) -> Result<$type_ident, E>
where E: ::serde::de::Error, where E: ::serde::de::Error,
{ {
Ok($result) Ok($type_ident)
} }
#[inline] #[inline]
fn visit_named_unit< fn visit_named_unit<
E: ::serde::de::Error, E: ::serde::de::Error,
>(&mut self, name: &str) -> Result<$type_ident, E> { >(&mut self, name: &str) -> Result<$type_ident, E> {
if name == $struct_name { if name == $type_name {
self.visit_unit() self.visit_unit()
} else { } else {
Err(::serde::de::Error::syntax_error()) Err(::serde::de::Error::syntax_error())
@@ -311,45 +228,45 @@ fn deserialize_unit_struct(
} }
} }
$state.visit(__Visitor) deserializer.visit(__Visitor)
}) })
} }
fn deserialize_tuple_struct( fn deserialize_tuple_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_ident: Ident, type_ident: Ident,
struct_path: ast::Path, impl_generics: &ast::Generics,
fields: &[Span], ty: P<ast::Ty>,
state: P<ast::Expr>, fields: usize,
trait_generics: &ast::Generics,
visitor_item: P<ast::Item>,
visitor_ty: P<ast::Ty>,
visitor_expr: P<ast::Expr>,
value_ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &trait_generics.where_clause; let where_clause = &impl_generics.where_clause;
let field_names: Vec<ast::Ident> = (0 .. fields.len()) let field_names: Vec<ast::Ident> = (0 .. fields)
.map(|i| builder.id(&format!("__field{}", i))) .map(|i| builder.id(&format!("__field{}", i)))
.collect(); .collect();
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
impl_generics,
);
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
builder, builder,
struct_path, builder.path().id(type_ident).build(),
&field_names, &field_names,
); );
let struct_name = builder.expr().str(struct_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { quote_expr!(cx, {
$visitor_item $visitor_item
impl $trait_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $impl_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $value_ty; type Value = $ty;
fn visit_seq<__V>(&mut self, mut visitor: __V) -> Result<$value_ty, __V::Error> fn visit_seq<__V>(&mut self, mut visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::SeqVisitor, where __V: ::serde::de::SeqVisitor,
{ {
$visit_seq_expr $visit_seq_expr
@@ -357,10 +274,10 @@ fn deserialize_tuple_struct(
fn visit_named_seq<__V>(&mut self, fn visit_named_seq<__V>(&mut self,
name: &str, name: &str,
visitor: __V) -> Result<$value_ty, __V::Error> visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::SeqVisitor, where __V: ::serde::de::SeqVisitor,
{ {
if name == $struct_name { if name == $type_name {
self.visit_seq(visitor) self.visit_seq(visitor)
} else { } else {
Err(::serde::de::Error::syntax_error()) Err(::serde::de::Error::syntax_error())
@@ -368,7 +285,7 @@ fn deserialize_tuple_struct(
} }
} }
$state.visit($visitor_expr) deserializer.visit($visitor_expr)
}) })
} }
@@ -405,42 +322,42 @@ fn deserialize_seq(
}) })
} }
fn deserialize_struct_named_fields( fn deserialize_struct(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_ident: Ident, type_ident: Ident,
struct_path: ast::Path, impl_generics: &ast::Generics,
fields: &[Ident], ty: P<ast::Ty>,
state: P<ast::Expr>,
struct_def: &StructDef, struct_def: &StructDef,
trait_generics: &ast::Generics, fields: Vec<Ident>,
visitor_item: P<ast::Item>,
visitor_ty: P<ast::Ty>,
visitor_expr: P<ast::Expr>,
value_ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &trait_generics.where_clause; let where_clause = &impl_generics.where_clause;
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
impl_generics,
);
let (field_visitor, visit_map_expr) = deserialize_struct_visitor( let (field_visitor, visit_map_expr) = deserialize_struct_visitor(
cx, cx,
builder, builder,
struct_def, struct_def,
struct_path, builder.path().id(type_ident).build(),
fields, fields,
); );
let struct_name = builder.expr().str(struct_ident); let type_name = builder.expr().str(type_ident);
quote_expr!(cx, { quote_expr!(cx, {
$field_visitor $field_visitor
$visitor_item $visitor_item
impl $trait_generics ::serde::de::Visitor for $visitor_ty $where_clause { impl $impl_generics ::serde::de::Visitor for $visitor_ty $where_clause {
type Value = $value_ty; type Value = $ty;
#[inline] #[inline]
fn visit_map<__V>(&mut self, mut visitor: __V) -> Result<$value_ty, __V::Error> fn visit_map<__V>(&mut self, mut visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::MapVisitor, where __V: ::serde::de::MapVisitor,
{ {
$visit_map_expr $visit_map_expr
@@ -449,10 +366,10 @@ fn deserialize_struct_named_fields(
#[inline] #[inline]
fn visit_named_map<__V>(&mut self, fn visit_named_map<__V>(&mut self,
name: &str, name: &str,
visitor: __V) -> Result<$value_ty, __V::Error> visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::MapVisitor, where __V: ::serde::de::MapVisitor,
{ {
if name == $struct_name { if name == $type_name {
self.visit_map(visitor) self.visit_map(visitor)
} else { } else {
Err(::serde::de::Error::syntax_error()) Err(::serde::de::Error::syntax_error())
@@ -460,7 +377,7 @@ fn deserialize_struct_named_fields(
} }
} }
$state.visit($visitor_expr) deserializer.visit($visitor_expr)
}) })
} }
@@ -469,7 +386,7 @@ fn deserialize_map(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_path: ast::Path, struct_path: ast::Path,
field_names: &[Ident], field_names: &[Ident],
fields: &[Ident], fields: Vec<Ident>,
struct_def: &StructDef, struct_def: &StructDef,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
// Declare each field. // Declare each field.
@@ -510,10 +427,16 @@ fn deserialize_map(
let result = builder.expr().struct_path(struct_path) let result = builder.expr().struct_path(struct_path)
.with_id_exprs( .with_id_exprs(
fields.iter() struct_def.fields.iter()
.zip(field_names.iter()) .zip(field_names.iter())
.map(|(name, field)| { .map(|(field, local)| {
(name.clone(), builder.expr().id(field)) (
match field.node.kind {
ast::NamedField(name, _) => name.clone(),
ast::UnnamedField(_) => panic!("struct contains unnamed fields"),
},
builder.expr().id(local),
)
}) })
) )
.build(); .build();
@@ -532,60 +455,47 @@ fn deserialize_map(
}) })
} }
fn deserialize_enum( fn deserialize_item_enum(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
fields: &[(Ident, Span, StaticFields)], impl_generics: &ast::Generics,
state: P<ast::Expr>, ty: P<ast::Ty>,
enum_def: &EnumDef, enum_def: &EnumDef,
trait_generics: &ast::Generics,
type_generics: &ast::Generics,
visitor_item: P<ast::Item>,
visitor_ty: P<ast::Ty>,
visitor_expr: P<ast::Expr>,
value_ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &trait_generics.where_clause; let where_clause = &impl_generics.where_clause;
let type_name = builder.expr().str(type_ident); let type_name = builder.expr().str(type_ident);
// Match arms to extract a variant from a string // Match arms to extract a variant from a string
let variant_arms: Vec<_> = fields.iter() let variant_arms: Vec<_> = enum_def.variants.iter()
.zip(enum_def.variants.iter()) .map(|variant| {
.map(|(&(name, _, ref fields), variant)| { deserialize_variant(
let value = deserialize_enum_variant(
cx, cx,
builder, builder,
type_ident, type_ident,
name, impl_generics,
fields, ty.clone(),
builder.expr().id("visitor"),
variant, variant,
visitor_item.clone(), )
visitor_ty.clone(),
visitor_expr.clone(),
&value_ty,
&trait_generics,
);
let s = builder.expr().str(name);
quote_arm!(cx, $s => $value,)
}) })
.collect(); .collect();
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
impl_generics,
);
quote_expr!(cx, { quote_expr!(cx, {
$visitor_item $visitor_item
impl $trait_generics ::serde::de::Visitor impl $impl_generics ::serde::de::Visitor for $visitor_ty $where_clause {
for __Visitor $type_generics type Value = $ty;
$where_clause {
type Value = $value_ty;
fn visit_enum<__V>(&mut self, fn visit_enum<__V>(&mut self,
name: &str, name: &str,
variant: &str, variant: &str,
visitor: __V) -> Result<$value_ty, __V::Error> visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::EnumVisitor, where __V: ::serde::de::EnumVisitor,
{ {
if name == $type_name { if name == $type_name {
@@ -597,7 +507,7 @@ fn deserialize_enum(
fn visit_variant<__V>(&mut self, fn visit_variant<__V>(&mut self,
name: &str, name: &str,
mut visitor: __V) -> Result<$value_ty, __V::Error> mut visitor: __V) -> Result<$ty, __V::Error>
where __V: ::serde::de::EnumVisitor where __V: ::serde::de::EnumVisitor
{ {
match name { match name {
@@ -607,164 +517,154 @@ fn deserialize_enum(
} }
} }
$state.visit_enum($visitor_expr) deserializer.visit_enum($visitor_expr)
}) })
} }
fn deserialize_enum_variant( fn deserialize_variant(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
variant_ident: Ident, generics: &ast::Generics,
fields: &StaticFields, ty: P<ast::Ty>,
state: P<ast::Expr>, variant: &ast::Variant,
variant: &P<ast::Variant>, ) -> ast::Arm {
visitor_item: P<ast::Item>, let variant_ident = variant.node.name;
visitor_ty: P<ast::Ty>, let variant_name = builder.expr().str(variant_ident);
visitor_expr: P<ast::Expr>,
value_ty: &P<ast::Ty>,
trait_generics: &ast::Generics,
) -> P<ast::Expr> {
let variant_path = builder.path()
.ids(&[type_ident, variant_ident])
.build();
match *fields { match variant.node.kind {
Unnamed(ref fields) if fields.is_empty() => { ast::TupleVariantKind(ref args) if args.is_empty() => {
quote_expr!(cx, { quote_arm!(cx,
try!($state.visit_unit()); $variant_name => {
Ok($variant_path) try!(visitor.visit_unit());
}) Ok($type_ident::$variant_ident)
} }
Unnamed(ref fields) => {
deserialize_enum_variant_seq(
cx,
builder,
fields.len(),
variant_path,
trait_generics,
state,
visitor_ty,
value_ty,
) )
} }
Named(ref fields) => { ast::TupleVariantKind(ref args) => {
let fields: Vec<_> = fields.iter() let fields: Vec<ast::Ident> = (0 .. args.len())
.map(|&(field, _)| field.clone()) .map(|i| builder.id(format!("__field{}", i)))
.collect(); .collect();
deserialize_enum_variant_map( let expr = deserialize_tuple_variant(
cx, cx,
builder, builder,
&fields, type_ident,
variant_path, variant_ident,
trait_generics, generics,
state, ty,
visitor_item, fields,
visitor_ty, );
visitor_expr,
value_ty, quote_arm!(cx, $variant_name => { $expr })
variant, }
) ast::StructVariantKind(ref struct_def) => {
let fields: Vec<_> = (0 .. struct_def.fields.len())
.map(|i| builder.id(format!("__field{}", i)))
.collect();
let expr = deserialize_struct_variant(
cx,
builder,
type_ident,
variant_ident,
generics,
ty,
struct_def,
fields,
);
quote_arm!(cx, $variant_name => { $expr })
} }
} }
} }
fn deserialize_enum_variant_seq( fn deserialize_tuple_variant(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
fields: usize, type_ident: ast::Ident,
variant_path: ast::Path, variant_ident: ast::Ident,
trait_generics: &ast::Generics, generics: &ast::Generics,
state: P<ast::Expr>, ty: P<ast::Ty>,
visitor_ty: P<ast::Ty>, fields: Vec<Ident>,
value_ty: &P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &trait_generics.where_clause; let where_clause = &generics.where_clause;
// Create the field names for the fields. // Create the field names for the fields.
let field_names: Vec<ast::Ident> = (0 .. fields) let field_names: Vec<ast::Ident> = (0 .. fields.len())
.map(|i| token::str_to_ident(&format!("__field{}", i))) .map(|i| token::str_to_ident(&format!("__field{}", i)))
.collect(); .collect();
let (visitor_item, visitor_expr) = deserialize_visitor( let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder, builder,
trait_generics, generics,
); );
let visit_seq_expr = deserialize_seq( let visit_seq_expr = deserialize_seq(
cx, cx,
builder, builder,
variant_path, builder.path().id(type_ident).id(variant_ident).build(),
&field_names, &field_names,
); );
quote_expr!(cx, { quote_expr!(cx, {
$visitor_item $visitor_item
impl $trait_generics ::serde::de::EnumSeqVisitor impl $generics ::serde::de::EnumSeqVisitor for $visitor_ty $where_clause {
for $visitor_ty type Value = $ty;
$where_clause {
type Value = $value_ty;
fn visit< fn visit<
V: ::serde::de::SeqVisitor, V: ::serde::de::SeqVisitor,
>(&mut self, mut visitor: V) -> Result<$value_ty, V::Error> { >(&mut self, mut visitor: V) -> Result<$ty, V::Error> {
$visit_seq_expr $visit_seq_expr
} }
} }
$state.visit_seq($visitor_expr) visitor.visit_seq($visitor_expr)
}) })
} }
fn deserialize_enum_variant_map( fn deserialize_struct_variant(
cx: &ExtCtxt, cx: &ExtCtxt,
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
fields: &[Ident], type_ident: ast::Ident,
variant_path: ast::Path, variant_ident: ast::Ident,
trait_generics: &ast::Generics, generics: &ast::Generics,
state: P<ast::Expr>, ty: P<ast::Ty>,
visitor_item: P<ast::Item>, struct_def: &ast::StructDef,
visitor_ty: P<ast::Ty>, fields: Vec<Ident>,
visitor_expr: P<ast::Expr>,
value_ty: &P<ast::Ty>,
variant: &P<ast::Variant>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let where_clause = &trait_generics.where_clause; let where_clause = &generics.where_clause;
let struct_def = match variant.node.kind { let (field_visitor, field_expr) = deserialize_struct_visitor(
ast::VariantKind::StructVariantKind(ref struct_def) => struct_def,
_ => panic!("Mismatched enum types")
};
let (field_visitor, visit_map_expr) = deserialize_struct_visitor(
cx, cx,
builder, builder,
struct_def, struct_def,
variant_path, builder.path().id(type_ident).id(variant_ident).build(),
fields, fields,
); );
let (visitor_item, visitor_ty, visitor_expr) = deserialize_visitor(
builder,
generics,
);
quote_expr!(cx, { quote_expr!(cx, {
$field_visitor $field_visitor
$visitor_item $visitor_item
impl $trait_generics ::serde::de::EnumMapVisitor impl $generics ::serde::de::EnumMapVisitor for $visitor_ty $where_clause {
for $visitor_ty type Value = $ty;
$where_clause {
type Value = $value_ty;
fn visit< fn visit<
V: ::serde::de::MapVisitor, V: ::serde::de::MapVisitor,
>(&mut self, mut visitor: V) -> Result<$value_ty, V::Error> { >(&mut self, mut visitor: V) -> Result<$ty, V::Error> {
$visit_map_expr $field_expr
} }
} }
$state.visit_map($visitor_expr) visitor.visit_map($visitor_expr)
}) })
} }
@@ -831,7 +731,7 @@ fn deserialize_struct_visitor(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
struct_def: &ast::StructDef, struct_def: &ast::StructDef,
struct_path: ast::Path, struct_path: ast::Path,
fields: &[Ident], fields: Vec<Ident>,
) -> (Vec<P<ast::Item>>, P<ast::Expr>) { ) -> (Vec<P<ast::Item>>, P<ast::Expr>) {
// Create the field names for the fields. // Create the field names for the fields.
+14 -16
View File
@@ -27,7 +27,7 @@ pub fn expand_derive_serialize(
let generics = match item.node { let generics = match item.node {
ast::ItemStruct(_, ref generics) => generics, ast::ItemStruct(_, ref generics) => generics,
ast::ItemEnum(_, ref generics) => generics, ast::ItemEnum(_, ref generics) => generics,
_ => cx.bug("expected ItemStruct or ItemEnum in derive(Deserialize)") _ => cx.bug("expected ItemStruct or ItemEnum in #[derive_serialize]")
}; };
let impl_generics = builder.from_generics(generics.clone()) let impl_generics = builder.from_generics(generics.clone())
@@ -36,7 +36,7 @@ pub fn expand_derive_serialize(
) )
.build(); .build();
let serialize_ty = builder.ty().path() let ty = builder.ty().path()
.segment(item.ident).with_generics(impl_generics.clone()).build() .segment(item.ident).with_generics(impl_generics.clone()).build()
.build(); .build();
@@ -45,14 +45,14 @@ pub fn expand_derive_serialize(
&builder, &builder,
item, item,
&impl_generics, &impl_generics,
serialize_ty.clone(), ty.clone(),
); );
let where_clause = &impl_generics.where_clause; let where_clause = &impl_generics.where_clause;
let impl_item = quote_item!(cx, let impl_item = quote_item!(cx,
#[automatically_derived] #[automatically_derived]
impl $impl_generics ::serde::ser::Serialize for $serialize_ty $where_clause { impl $impl_generics ::serde::ser::Serialize for $ty $where_clause {
fn serialize<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error> fn serialize<__S>(&self, serializer: &mut __S) -> Result<(), __S::Error>
where __S: ::serde::ser::Serializer, where __S: ::serde::ser::Serializer,
{ {
@@ -69,7 +69,7 @@ fn serialize_body(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
serialize_ty: P<ast::Ty>, ty: P<ast::Ty>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
match item.node { match item.node {
ast::ItemStruct(ref struct_def, _) => { ast::ItemStruct(ref struct_def, _) => {
@@ -78,11 +78,10 @@ fn serialize_body(
builder, builder,
item, item,
impl_generics, impl_generics,
serialize_ty, ty,
struct_def, struct_def,
) )
} }
ast::ItemEnum(ref enum_def, _) => { ast::ItemEnum(ref enum_def, _) => {
serialize_item_enum( serialize_item_enum(
cx, cx,
@@ -92,8 +91,7 @@ fn serialize_body(
enum_def, enum_def,
) )
} }
_ => cx.bug("expected ItemStruct or ItemEnum in #[derive_serialize]")
_ => cx.bug("expected ItemStruct or ItemEnum in derive_serialize")
} }
} }
@@ -102,7 +100,7 @@ fn serialize_item_struct(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
item: &Item, item: &Item,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
serialize_ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &ast::StructDef, struct_def: &ast::StructDef,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let mut named_fields = vec![]; let mut named_fields = vec![];
@@ -129,7 +127,7 @@ fn serialize_item_struct(
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
serialize_ty, ty,
unnamed_fields, unnamed_fields,
) )
} }
@@ -139,7 +137,7 @@ fn serialize_item_struct(
&builder, &builder,
item.ident, item.ident,
impl_generics, impl_generics,
serialize_ty, ty,
struct_def, struct_def,
named_fields, named_fields,
) )
@@ -165,13 +163,13 @@ fn serialize_tuple_struct(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
serialize_ty: P<ast::Ty>, ty: P<ast::Ty>,
fields: usize, fields: usize,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty() let value_ty = builder.ty()
.ref_() .ref_()
.lifetime("'__a") .lifetime("'__a")
.build_ty(serialize_ty); .build_ty(ty);
let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor( let (visitor_struct, visitor_impl) = serialize_tuple_struct_visitor(
cx, cx,
@@ -198,14 +196,14 @@ fn serialize_struct(
builder: &aster::AstBuilder, builder: &aster::AstBuilder,
type_ident: Ident, type_ident: Ident,
impl_generics: &ast::Generics, impl_generics: &ast::Generics,
serialize_ty: P<ast::Ty>, ty: P<ast::Ty>,
struct_def: &StructDef, struct_def: &StructDef,
fields: Vec<Ident>, fields: Vec<Ident>,
) -> P<ast::Expr> { ) -> P<ast::Expr> {
let value_ty = builder.ty() let value_ty = builder.ty()
.ref_() .ref_()
.lifetime("'__a") .lifetime("'__a")
.build_ty(serialize_ty.clone()); .build_ty(ty.clone());
let (visitor_struct, visitor_impl) = serialize_struct_visitor( let (visitor_struct, visitor_impl) = serialize_struct_visitor(
cx, cx,
+28 -28
View File
@@ -30,6 +30,30 @@ trait Trait {
#[derive_deserialize] #[derive_deserialize]
struct NamedUnit; struct NamedUnit;
#[derive(Debug, PartialEq)]
#[derive_serialize]
struct SerNamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
#[derive(Debug, PartialEq)]
#[derive_deserialize]
struct DeNamedTuple<A, B, C>(A, B, C);
#[derive(Debug, PartialEq)]
#[derive_serialize]
struct SerNamedMap<'a, 'b, A: 'a, B: 'b, C> {
a: &'a A,
b: &'b mut B,
c: C,
}
#[derive(Debug, PartialEq)]
#[derive_deserialize]
struct DeNamedMap<A, B, C> {
a: A,
b: B,
c: C,
}
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
#[derive_serialize] #[derive_serialize]
enum SerEnum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a { enum SerEnum<'a, B: 'a, C: /* Trait + */ 'a, D> where D: /* Trait + */ 'a {
@@ -135,14 +159,10 @@ fn test_named_unit() {
#[test] #[test]
fn test_ser_named_tuple() { fn test_ser_named_tuple() {
#[derive(Debug, PartialEq)]
#[derive_serialize]
struct NamedTuple<'a, 'b, A: 'a, B: 'b, C>(&'a A, &'b mut B, C);
let a = 5; let a = 5;
let mut b = 6; let mut b = 6;
let c = 7; let c = 7;
let named_tuple = NamedTuple(&a, &mut b, c); let named_tuple = SerNamedTuple(&a, &mut b, c);
assert_eq!( assert_eq!(
json::to_string(&named_tuple).unwrap(), json::to_string(&named_tuple).unwrap(),
@@ -157,13 +177,9 @@ fn test_ser_named_tuple() {
#[test] #[test]
fn test_de_named_tuple() { fn test_de_named_tuple() {
#[derive(Debug, PartialEq)]
#[derive_deserialize]
struct NamedTuple<A, B, C>(A, B, C);
assert_eq!( assert_eq!(
json::from_str("[1,2,3]").unwrap(), json::from_str("[1,2,3]").unwrap(),
NamedTuple(1, 2, 3) DeNamedTuple(1, 2, 3)
); );
assert_eq!( assert_eq!(
@@ -178,18 +194,10 @@ fn test_de_named_tuple() {
#[test] #[test]
fn test_ser_named_map() { fn test_ser_named_map() {
#[derive(Debug, PartialEq)]
#[derive_serialize]
struct NamedMap<'a, 'b, A: 'a, B: 'b, C> {
a: &'a A,
b: &'b mut B,
c: C,
}
let a = 5; let a = 5;
let mut b = 6; let mut b = 6;
let c = 7; let c = 7;
let named_map = NamedMap { let named_map = SerNamedMap {
a: &a, a: &a,
b: &mut b, b: &mut b,
c: c, c: c,
@@ -212,15 +220,7 @@ fn test_ser_named_map() {
#[test] #[test]
fn test_de_named_map() { fn test_de_named_map() {
#[derive(Debug, PartialEq)] let v = DeNamedMap {
#[derive_deserialize]
struct NamedMap<A, B, C> {
a: A,
b: B,
c: C,
}
let v = NamedMap {
a: 5, a: 5,
b: 6, b: 6,
c: 7, c: 7,