Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reuse a single ContentRefDeserializer throughout untagged enum deserialization #2470

Merged
merged 1 commit into from Jun 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions serde/src/private/de.rs
Expand Up @@ -2193,6 +2193,14 @@ mod content {
}
}

impl<'a, 'de: 'a, E> Copy for ContentRefDeserializer<'a, 'de, E> {}

impl<'a, 'de: 'a, E> Clone for ContentRefDeserializer<'a, 'de, E> {
fn clone(&self) -> Self {
*self
}
}

struct EnumRefDeserializer<'a, 'de: 'a, E>
where
E: de::Error,
Expand Down
22 changes: 7 additions & 15 deletions serde_derive/src/de.rs
Expand Up @@ -1172,13 +1172,7 @@ fn deserialize_enum(
Some(variant_idx) => {
let (tagged, untagged) = variants.split_at(variant_idx);
let tagged_frag = Expr(deserialize_homogeneous_enum(params, tagged, cattrs));
let tagged_frag = |deserializer| {
Some(Expr(quote_block! {
let __deserializer = #deserializer;
#tagged_frag
}))
};
deserialize_untagged_enum_after(params, untagged, cattrs, tagged_frag)
deserialize_untagged_enum_after(params, untagged, cattrs, Some(tagged_frag))
}
None => deserialize_homogeneous_enum(params, variants, cattrs),
}
Expand Down Expand Up @@ -1689,17 +1683,16 @@ fn deserialize_untagged_enum(
variants: &[Variant],
cattrs: &attr::Container,
) -> Fragment {
deserialize_untagged_enum_after(params, variants, cattrs, |_| None)
let first_attempt = None;
deserialize_untagged_enum_after(params, variants, cattrs, first_attempt)
}

fn deserialize_untagged_enum_after(
params: &Parameters,
variants: &[Variant],
cattrs: &attr::Container,
first_attempt: impl FnOnce(TokenStream) -> Option<Expr>,
first_attempt: Option<Expr>,
) -> Fragment {
let deserializer =
quote!(_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content));
let attempts = variants
.iter()
.filter(|variant| !variant.attrs.skip_deserializing())
Expand All @@ -1708,12 +1701,10 @@ fn deserialize_untagged_enum_after(
params,
variant,
cattrs,
deserializer.clone(),
quote!(__deserializer),
))
});
let attempts = first_attempt(deserializer.clone())
.into_iter()
.chain(attempts);
let attempts = first_attempt.into_iter().chain(attempts);
// TODO this message could be better by saving the errors from the failed
// attempts. The heuristic used by TOML was to count the number of fields
// processed before an error, and use the error that happened after the
Expand All @@ -1728,6 +1719,7 @@ fn deserialize_untagged_enum_after(

quote_block! {
let __content = try!(<_serde::__private::de::Content as _serde::Deserialize>::deserialize(__deserializer));
let __deserializer = _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content);

#(
if let _serde::__private::Ok(__ok) = #attempts {
Expand Down