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
2 changed files with 43 additions and 34 deletions
+29 -34
View File
@@ -1377,42 +1377,37 @@ fn deserialize_adjacently_tagged_enum(
} }
}; };
fn is_unit(variant: &Variant) -> bool { let arms = variants
match variant.style { .iter()
Style::Unit => true, .enumerate()
Style::Struct | Style::Tuple | Style::Newtype => false, .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! { let arm = match variant.style {
_serde::export::Err(<__A::Error as _serde::de::Error>::missing_field(#content)) Style::Unit => quote! {
}; _serde::export::Ok(#this::#variant_ident)
if variants.iter().any(is_unit) { },
let fallthrough = if variants.iter().all(is_unit) { Style::Newtype if variant.attrs.deserialize_with().is_none() => {
None let span = variant.original.span();
} else { let func = quote_spanned!(span=> _serde::private::de::missing_field);
Some(quote! { quote! {
_ => #missing_content #func(#content).map(#this::#variant_ident)
}) }
};
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),
} }
}); _ => return None,
missing_content = quote! { };
match __field { Some(quote! {
#(#arms)* __Field::#variant_index => #arm,
#fallthrough })
} });
}; 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. // Advance the map by one key, returning early in case of error.
let next_key = quote! { let next_key = quote! {
+14
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 // tuple with tag first
assert_tokens( assert_tokens(
&AdjacentlyTagged::Tuple::<u8>(1, 1), &AdjacentlyTagged::Tuple::<u8>(1, 1),