Skip to content

Commit

Permalink
Merge pull request #1458 from Lymia/master
Browse files Browse the repository at this point in the history
Implements alias annotation and allow multiple deserialization renames.
  • Loading branch information
dtolnay authored Jan 19, 2019
2 parents 9ec68e5 + 8bbc299 commit 96576c4
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 145 deletions.
134 changes: 57 additions & 77 deletions serde_derive/src/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,33 +1140,25 @@ fn deserialize_enum(
}
}

fn deserialize_externally_tagged_enum(
params: &Parameters,
fn prepare_enum_variant_enum(
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();

let type_name = cattrs.name().deserialize_name();

let expecting = format!("enum {}", params.type_name());

) -> (TokenStream, Stmts) {
let variant_names_idents: Vec<_> = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
.map(|(i, variant)| {
(variant.attrs.name().deserialize_name(), field_i(i), variant.attrs.aliases())
})
.collect();

let other_idx = variants
.iter()
.position(|ref variant| variant.attrs.other());

let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
let variant_names = variant_names_idents.iter().map(|&(ref name, _, _)| name);
quote! {
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
Expand All @@ -1179,6 +1171,24 @@ fn deserialize_externally_tagged_enum(
other_idx,
));

(variants_stmt, variant_visitor)
}

fn deserialize_externally_tagged_enum(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
let this = &params.this;
let (de_impl_generics, de_ty_generics, ty_generics, where_clause) =
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();

let type_name = cattrs.name().deserialize_name();
let expecting = format!("enum {}", params.type_name());

let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);

// Match arms to extract a variant from a string
let variant_arms = variants
.iter()
Expand Down Expand Up @@ -1261,30 +1271,7 @@ fn deserialize_internally_tagged_enum(
cattrs: &attr::Container,
tag: &str,
) -> Fragment {
let variant_names_idents: Vec<_> = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
.collect();

let other_idx = variants
.iter()
.position(|ref variant| variant.attrs.other());

let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
quote! {
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
};

let variant_visitor = Stmts(deserialize_generated_identifier(
&variant_names_idents,
cattrs,
true,
other_idx,
));
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);

// Match arms to extract a variant from a string
let variant_arms = variants
Expand Down Expand Up @@ -1335,30 +1322,7 @@ fn deserialize_adjacently_tagged_enum(
split_with_de_lifetime(params);
let delife = params.borrowed.de_lifetime();

let variant_names_idents: Vec<_> = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.map(|(i, variant)| (variant.attrs.name().deserialize_name(), field_i(i)))
.collect();

let other_idx = variants
.iter()
.position(|ref variant| variant.attrs.other());

let variants_stmt = {
let variant_names = variant_names_idents.iter().map(|&(ref name, _)| name);
quote! {
const VARIANTS: &'static [&'static str] = &[ #(#variant_names),* ];
}
};

let variant_visitor = Stmts(deserialize_generated_identifier(
&variant_names_idents,
cattrs,
true,
other_idx,
));
let (variants_stmt, variant_visitor) = prepare_enum_variant_enum(variants, cattrs);

let variant_arms: &Vec<_> = &variants
.iter()
Expand Down Expand Up @@ -1870,13 +1834,13 @@ fn deserialize_untagged_newtype_variant(
}

fn deserialize_generated_identifier(
fields: &[(String, Ident)],
fields: &[(String, Ident, Vec<String>)],
cattrs: &attr::Container,
is_variant: bool,
other_idx: Option<usize>,
) -> Fragment {
let this = quote!(__Field);
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident)| ident).collect();
let field_idents: &Vec<_> = &fields.iter().map(|&(_, ref ident, _)| ident).collect();

let (ignore_variant, fallthrough) = if !is_variant && cattrs.has_flatten() {
let ignore_variant = quote!(__other(_serde::private::de::Content<'de>),);
Expand Down Expand Up @@ -1977,11 +1941,12 @@ fn deserialize_custom_identifier(
(
variant.attrs.name().deserialize_name(),
variant.ident.clone(),
variant.attrs.aliases(),
)
})
.collect();

let names = names_idents.iter().map(|&(ref name, _)| name);
let names = names_idents.iter().map(|&(ref name, _, _)| name);

let names_const = if fallthrough.is_some() {
None
Expand Down Expand Up @@ -2032,24 +1997,33 @@ fn deserialize_custom_identifier(

fn deserialize_identifier(
this: &TokenStream,
fields: &[(String, Ident)],
fields: &[(String, Ident, Vec<String>)],
is_variant: bool,
fallthrough: Option<TokenStream>,
collect_other_fields: bool,
) -> Fragment {
let field_strs = fields.iter().map(|&(ref name, _)| name);
let field_borrowed_strs = fields.iter().map(|&(ref name, _)| name);
let field_bytes = fields
let mut flat_fields = Vec::new();
for &(_, ref ident, ref aliases) in fields {
flat_fields.extend(aliases.iter().map(|alias| (alias, ident)))
}

let field_strs = flat_fields.iter().map(|&(ref name, _)| name);
let field_borrowed_strs = flat_fields.iter().map(|&(ref name, _)| name);
let field_bytes = flat_fields
.iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));
let field_borrowed_bytes = fields
let field_borrowed_bytes = flat_fields
.iter()
.map(|&(ref name, _)| Literal::byte_string(name.as_bytes()));

let constructors: &Vec<_> = &fields
let constructors: &Vec<_> = &flat_fields
.iter()
.map(|&(_, ref ident)| quote!(#this::#ident))
.collect();
let main_constructors: &Vec<_> = &fields
.iter()
.map(|&(_, ref ident, _)| quote!(#this::#ident))
.collect();

let expecting = if is_variant {
"variant identifier"
Expand Down Expand Up @@ -2237,7 +2211,7 @@ fn deserialize_identifier(
{
match __value {
#(
#variant_indices => _serde::export::Ok(#constructors),
#variant_indices => _serde::export::Ok(#main_constructors),
)*
_ => _serde::export::Err(_serde::de::Error::invalid_value(
_serde::de::Unexpected::Unsigned(__value),
Expand Down Expand Up @@ -2300,11 +2274,13 @@ fn deserialize_struct_as_struct_visitor(
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing())
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
.map(|(i, field)| {
(field.attrs.name().deserialize_name(), field_i(i), field.attrs.aliases())
})
.collect();

let fields_stmt = {
let field_names = field_names_idents.iter().map(|&(ref name, _)| name);
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name);
quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
Expand All @@ -2327,7 +2303,9 @@ fn deserialize_struct_as_map_visitor(
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing() && !field.attrs.flatten())
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
.map(|(i, field)| {
(field.attrs.name().deserialize_name(), field_i(i), field.attrs.aliases())
})
.collect();

let field_visitor = deserialize_generated_identifier(&field_names_idents, cattrs, false, None);
Expand Down Expand Up @@ -2558,11 +2536,13 @@ fn deserialize_struct_as_struct_in_place_visitor(
.iter()
.enumerate()
.filter(|&(_, field)| !field.attrs.skip_deserializing())
.map(|(i, field)| (field.attrs.name().deserialize_name(), field_i(i)))
.map(|(i, field)| {
(field.attrs.name().deserialize_name(), field_i(i), field.attrs.aliases())
})
.collect();

let fields_stmt = {
let field_names = field_names_idents.iter().map(|&(ref name, _)| name);
let field_names = field_names_idents.iter().map(|&(ref name, _, _)| name);
quote_block! {
const FIELDS: &'static [&'static str] = &[ #(#field_names),* ];
}
Expand Down
Loading

0 comments on commit 96576c4

Please sign in to comment.