Allow optional content field for adjacently tagged newtype variants

* Deserialize adjacently tagged newtype variants with optional content as None instead of erroring when content field is missing

* refactor to remove duplicate code and remove panic
This commit is contained in:
asdsad 2020-05-10 04:58:28 +01:00 committed by GitHub
parent 3c97e1b9a9
commit 172edc4cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 34 deletions

View File

@ -1377,42 +1377,37 @@ fn deserialize_adjacently_tagged_enum(
}
};
fn is_unit(variant: &Variant) -> bool {
match variant.style {
Style::Unit => true,
Style::Struct | Style::Tuple | Style::Newtype => false,
}
}
let arms = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing())
.filter_map(|(i, variant)| {
let variant_index = field_i(i);
let variant_ident = &variant.ident;
let mut missing_content = quote! {
_serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
};
if variants.iter().any(is_unit) {
let fallthrough = if variants.iter().all(is_unit) {
None
} else {
Some(quote! {
_ => #missing_content
})
};
let arms = variants
.iter()
.enumerate()
.filter(|&(_, variant)| !variant.attrs.skip_deserializing() && is_unit(variant))
.map(|(i, variant)| {
let variant_index = field_i(i);
let variant_ident = &variant.ident;
quote! {
__Field::#variant_index => _serde::export::Ok(#this::#variant_ident),
let arm = match variant.style {
Style::Unit => quote! {
_serde::export::Ok(#this::#variant_ident)
},
Style::Newtype if variant.attrs.deserialize_with().is_none() => {
let span = variant.original.span();
let func = quote_spanned!(span=> _serde::private::de::missing_field);
quote! {
#func(#content).map(#this::#variant_ident)
}
}
});
missing_content = quote! {
match __field {
#(#arms)*
#fallthrough
}
};
}
_ => return None,
};
Some(quote! {
__Field::#variant_index => #arm,
})
});
let missing_content = quote! {
match __field {
#(#arms)*
_ => _serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content))
}
};
// Advance the map by one key, returning early in case of error.
let next_key = quote! {

View File

@ -1145,6 +1145,20 @@ fn test_adjacently_tagged_enum() {
],
);
// optional newtype with no content field
assert_de_tokens(
&AdjacentlyTagged::Newtype::<Option<u8>>(None),
&[
Token::Struct {
name: "AdjacentlyTagged",
len: 1,
},
Token::Str("t"),
Token::Str("Newtype"),
Token::StructEnd,
],
);
// tuple with tag first
assert_tokens(
&AdjacentlyTagged::Tuple::<u8>(1, 1),