Add serde default attribute for fields
When annotated with #[serde(default)], a field gets a default value using std:default::Default, and will not error when decoding if the field is missing from the input. Addresses #9
This commit is contained in:
parent
5f46adb2d0
commit
b6fc68c030
@ -9,6 +9,8 @@ use syntax::ast::{
|
||||
Item,
|
||||
Expr,
|
||||
MutMutable,
|
||||
StructDef,
|
||||
EnumDef,
|
||||
};
|
||||
use syntax::ast;
|
||||
use syntax::codemap::{Span, respan};
|
||||
@ -57,8 +59,8 @@ fn expand_derive_serialize(
|
||||
sp: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Item,
|
||||
mut push: Box<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));
|
||||
|
||||
@ -462,8 +464,8 @@ pub fn expand_derive_deserialize(
|
||||
sp: Span,
|
||||
mitem: &MetaItem,
|
||||
item: &Item,
|
||||
mut push: Box<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));
|
||||
|
||||
@ -518,7 +520,7 @@ fn deserialize_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) ->
|
||||
let state = substr.nonself_args[0].clone();
|
||||
|
||||
match *substr.fields {
|
||||
StaticStruct(_, ref fields) => {
|
||||
StaticStruct(ref struct_def, ref fields) => {
|
||||
deserialize_struct(
|
||||
cx,
|
||||
span,
|
||||
@ -526,15 +528,17 @@ fn deserialize_substructure(cx: &ExtCtxt, span: Span, substr: &Substructure) ->
|
||||
substr.type_ident,
|
||||
cx.path(span, vec![substr.type_ident]),
|
||||
fields,
|
||||
state)
|
||||
state,
|
||||
struct_def)
|
||||
}
|
||||
StaticEnum(_, ref fields) => {
|
||||
StaticEnum(ref enum_def, ref fields) => {
|
||||
deserialize_enum(
|
||||
cx,
|
||||
span,
|
||||
substr.type_ident,
|
||||
&fields,
|
||||
state)
|
||||
state,
|
||||
enum_def)
|
||||
}
|
||||
_ => cx.bug("expected StaticEnum or StaticStruct in derive(Deserialize)")
|
||||
}
|
||||
@ -548,6 +552,7 @@ fn deserialize_struct(
|
||||
struct_path: ast::Path,
|
||||
fields: &StaticFields,
|
||||
state: P<ast::Expr>,
|
||||
struct_def: &StructDef
|
||||
) -> P<ast::Expr> {
|
||||
match *fields {
|
||||
Unnamed(ref fields) => {
|
||||
@ -555,16 +560,16 @@ fn deserialize_struct(
|
||||
deserialize_struct_empty_fields(
|
||||
cx,
|
||||
span,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
struct_path,
|
||||
state)
|
||||
} else {
|
||||
deserialize_struct_unnamed_fields(
|
||||
cx,
|
||||
span,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
struct_path,
|
||||
&fields[],
|
||||
state)
|
||||
@ -574,11 +579,12 @@ fn deserialize_struct(
|
||||
deserialize_struct_named_fields(
|
||||
cx,
|
||||
span,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
type_ident,
|
||||
struct_ident,
|
||||
struct_path,
|
||||
&fields[],
|
||||
state)
|
||||
state,
|
||||
struct_def)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -714,6 +720,7 @@ fn deserialize_struct_named_fields(
|
||||
struct_path: ast::Path,
|
||||
fields: &[(Ident, Span)],
|
||||
state: P<ast::Expr>,
|
||||
struct_def: &StructDef,
|
||||
) -> P<ast::Expr> {
|
||||
let struct_name = cx.expr_str(span, token::get_ident(struct_ident));
|
||||
|
||||
@ -735,6 +742,7 @@ fn deserialize_struct_named_fields(
|
||||
struct_path,
|
||||
&field_names[],
|
||||
fields,
|
||||
struct_def
|
||||
);
|
||||
|
||||
quote_expr!(cx, {
|
||||
@ -842,18 +850,50 @@ fn declare_map_field_deserializer(
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
fn default_value(field: &ast::StructField) -> bool {
|
||||
field.node.attrs.iter()
|
||||
.any(|sa|
|
||||
match &sa.node.value.node {
|
||||
&ast::MetaItem_::MetaList(ref n, ref vals) => {
|
||||
if n == &"serde" {
|
||||
vals.iter()
|
||||
.map(|mi|
|
||||
match &mi.node {
|
||||
&ast::MetaItem_::MetaWord(ref n) => {
|
||||
n == &"default"
|
||||
},
|
||||
_ => false
|
||||
})
|
||||
.any(|x| x)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => false
|
||||
} )
|
||||
}
|
||||
|
||||
fn declare_visit_map(
|
||||
cx: &ExtCtxt,
|
||||
span: Span,
|
||||
struct_path: ast::Path,
|
||||
field_names: &[Ident],
|
||||
fields: &[(Ident, Span)],
|
||||
struct_def: &StructDef,
|
||||
) -> P<ast::Expr> {
|
||||
|
||||
// Declare each field.
|
||||
let let_values: Vec<P<ast::Stmt>> = field_names.iter()
|
||||
.map(|field| {
|
||||
quote_stmt!(cx, let mut $field = None;)
|
||||
.zip(struct_def.fields.iter())
|
||||
.map(|(field, sf)| {
|
||||
if default_value(sf) {
|
||||
quote_stmt!(
|
||||
cx,
|
||||
let mut $field = Some(::std::default::Default::default());)
|
||||
} else {
|
||||
quote_stmt!(cx, let mut $field = None;)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -912,12 +952,14 @@ fn deserialize_enum(
|
||||
type_ident: Ident,
|
||||
fields: &[(Ident, Span, StaticFields)],
|
||||
state: P<ast::Expr>,
|
||||
enum_def: &EnumDef,
|
||||
) -> P<ast::Expr> {
|
||||
let type_name = cx.expr_str(span, token::get_ident(type_ident));
|
||||
|
||||
// Match arms to extract a variant from a string
|
||||
let variant_arms: Vec<ast::Arm> = fields.iter()
|
||||
.map(|&(name, span, ref fields)| {
|
||||
.zip(enum_def.variants.iter())
|
||||
.map(|(&(name, span, ref fields), variant_ptr)| {
|
||||
let value = deserialize_enum_variant(
|
||||
cx,
|
||||
span,
|
||||
@ -925,6 +967,7 @@ fn deserialize_enum(
|
||||
name,
|
||||
fields,
|
||||
cx.expr_ident(span, cx.ident_of("visitor")),
|
||||
variant_ptr,
|
||||
);
|
||||
|
||||
let s = cx.expr_str(span, token::get_ident(name));
|
||||
@ -969,6 +1012,7 @@ fn deserialize_enum_variant(
|
||||
variant_ident: Ident,
|
||||
fields: &StaticFields,
|
||||
state: P<ast::Expr>,
|
||||
variant_ptr: &P<ast::Variant>,
|
||||
) -> P<ast::Expr> {
|
||||
let variant_path = cx.path(span, vec![type_ident, variant_ident]);
|
||||
|
||||
@ -1030,6 +1074,10 @@ fn deserialize_enum_variant(
|
||||
variant_path,
|
||||
&field_names[],
|
||||
fields,
|
||||
match variant_ptr.node.kind {
|
||||
ast::VariantKind::StructVariantKind(ref sd) => &*sd,
|
||||
_ => panic!("Mismatched enum types")
|
||||
},
|
||||
);
|
||||
|
||||
quote_expr!(cx, {
|
||||
|
Loading…
Reference in New Issue
Block a user