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:
parent
3c97e1b9a9
commit
172edc4cf4
@ -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! {
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user