Repository: serde-rs/serde
File: serde_derive/src/de.rs (Rust)

Code before:
            FIELDS,
            __Visitor {
                marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
                lifetime: _serde::__private::PhantomData,
            },
        )
    }
}

fn deserialize_untagged_enum(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
) -> Fragment {
    deserialize_untagged_enum_after(params, variants, cattrs, None::<fn(_) -> _>)
}

fn deserialize_untagged_enum_after(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
    first_attempt: Option<impl FnOnce(TokenStream) -> Expr>,
) -> Fragment {
    let deserializer = || quote!(
        _serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content)
    );
    let attempts = variants
        .iter()
        .filter(|variant| !variant.attrs.skip_deserializing())
        .map(|variant| {
            Expr(deserialize_untagged_variant(
                params,
                variant,
                cattrs,
                deserializer(),
            ))
        });
    let attempts = first_attempt.map(|f| f(deserializer())).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
    // largest number of fields. I'm not sure I like that. Maybe it would be
    // better to save all the errors and combine them into one message that
    // explains why none of the variants matched.
    let fallthrough_msg = format!(
        "data did not match any variant of untagged enum {}",
        params.type_name()
    );
    let fallthrough_msg = cattrs.expecting().unwrap_or(&fallthrough_msg);

    quote_block! {

Review comment (refactor):
I think you could avoid the closure and just clone the TokenStream.

This way you can also make the `first_attempt` argument be `impl FnOnce(&TokenStream) -> Option<Expr>`, which should simplify the `None` caller.

Code after:
        _serde::Deserializer::deserialize_struct(
            __deserializer,
            #type_name,
            FIELDS,
            __Visitor {
                marker: _serde::__private::PhantomData::<#this_type #ty_generics>,
                lifetime: _serde::__private::PhantomData,
            },
        )
    }
}

fn deserialize_untagged_enum(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
) -> Fragment {
    deserialize_untagged_enum_after(params, variants, cattrs, |_| None)
}

fn deserialize_untagged_enum_after(
    params: &Parameters,
    variants: &[Variant],
    cattrs: &attr::Container,
    first_attempt: impl FnOnce(TokenStream) -> Option<Expr>,
) -> Fragment {
    let deserializer =
        quote!(_serde::__private::de::ContentRefDeserializer::<__D::Error>::new(&__content));
    let attempts = variants
        .iter()
        .filter(|variant| !variant.attrs.skip_deserializing())
        .map(|variant| {
            Expr(deserialize_untagged_variant(
                params,
                variant,
                cattrs,
                deserializer.clone(),
            ))
        });
    let attempts = first_attempt(deserializer.clone())
        .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
    // largest number of fields. I'm not sure I like that. Maybe it would be
    // better to save all the errors and combine them into one message that
    // explains why none of the variants matched.
    let fallthrough_msg = format!(
        "data did not match any variant of untagged enum {}",
        params.type_name()