Skip to main content

diesel_derives/
enum_.rs

1use proc_macro2::{Span, TokenStream};
2use syn::{Data, Ident, Result, spanned::Spanned};
3
4use crate::attrs::AttributeSpanWrapper;
5use crate::util::wrap_in_dummy_mod;
6
7const ERROR_MESSAGE: &str = "this derive can only be used on enums with exclusively unit-variants";
8
9pub fn derive(item: DeriveEnumInput) -> Result<TokenStream> {
10    let mut to_sql_impls = Vec::new();
11    let mut from_sql_impls = Vec::new();
12    for tpe in &item.sql_type_attrs {
13        let span = tpe.attribute_span;
14        let tpe = &tpe.item;
15        let sql_type = {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&tpe, &mut _s);
    _s
}quote::quote_spanned! {span=> #tpe};
16        let enum_name = &item.ident;
17        let has_explicit_discriminant = item.has_explicit_discriminants;
18        let variants = item
19            .variants
20            .iter()
21            .map(EnumVariant::as_diesel_enum_variant)
22            .collect::<Vec<_>>();
23        let variant_constructor = item.variants.iter().enumerate().map(|(idx, v)| {
24            let span = v.span;
25            let ident = &v.rust_name;
26            {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::ToTokens::to_tokens(&idx, &mut _s);
    ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Ok");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Parenthesis,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident_spanned(&mut _s, _span, "Self");
            ::quote::__private::push_colon2_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&ident, &mut _s);
            _s
        });
    _s
}quote::quote_spanned! {span=> #idx => Ok(Self::#ident)}
27        });
28        let variant_to_enum_variant_mapping = item.variants.iter().map(|v| {
29            let span = v.span;
30            let ident = &v.rust_name;
31            let enum_variant = v.as_diesel_enum_variant();
32            {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "Self");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&ident, &mut _s);
    ::quote::__private::push_fat_arrow_spanned(&mut _s, _span);
    ::quote::__private::push_and_spanned(&mut _s, _span);
    ::quote::ToTokens::to_tokens(&enum_variant, &mut _s);
    _s
}quote::quote_spanned! {span=> Self::#ident => &#enum_variant}
33        });
34
35        from_sql_impls.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "deserialize");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "FromSql");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&enum_name, &mut _s);
    ::quote::__private::push_ident(&mut _s, "where");
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "backend");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Backend");
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&has_explicit_discriminant, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&has_explicit_discriminant, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_shr(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Strategy");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "derives");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "enum_");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumMapping");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "from_sql");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "value");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "backend");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Backend");
                    ::quote::__private::push_gt(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "RawValue");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_lifetime(&mut _s, "\'_");
                    ::quote::__private::push_gt(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "deserialize");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Self");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "const");
                    ::quote::__private::push_ident(&mut _s, "VARIANTS");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Bracket,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "diesel");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "internal");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "derives");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "enum_");
                            ::quote::__private::push_colon2(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "EnumVariant");
                            _s
                        });
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Bracket,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut variants, i) = variants.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let variants =
                                        match variants.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    ::quote::ToTokens::to_tokens(&variants, &mut _s);
                                    ::quote::__private::push_comma(&mut _s);
                                }
                            }
                            _s
                        });
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "idx");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_shl(&mut _s);
                    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "sql_types");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&has_explicit_discriminant,
                        &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_shr(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Strategy");
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "internal");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "derives");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "enum_");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "EnumMapping");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_shr(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "map_from_database_value");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "value");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "stringify");
                            ::quote::__private::push_bang(&mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::ToTokens::to_tokens(&enum_name, &mut _s);
                                    _s
                                });
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "VARIANTS");
                            _s
                        });
                    ::quote::__private::push_question(&mut _s);
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "match");
                    ::quote::__private::push_ident(&mut _s, "idx");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut variant_constructor, i) =
                                    variant_constructor.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let variant_constructor =
                                        match variant_constructor.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    ::quote::ToTokens::to_tokens(&variant_constructor, &mut _s);
                                    ::quote::__private::push_comma(&mut _s);
                                }
                            }
                            ::quote::__private::push_underscore(&mut _s);
                            ::quote::__private::push_fat_arrow(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "unreachable");
                            ::quote::__private::push_bang(&mut _s);
                            ::quote::__private::push_group(&mut _s,
                                ::quote::__private::Delimiter::Parenthesis,
                                {
                                    let mut _s = ::quote::__private::TokenStream::new();
                                    ::quote::__private::parse(&mut _s,
                                        "\"We construct all relevant variants\"");
                                    _s
                                });
                            ::quote::__private::push_comma(&mut _s);
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote::quote! {
36            impl<__DB> diesel::deserialize::FromSql<#sql_type, __DB> for #enum_name
37            where
38                __DB: diesel::backend::Backend,
39                #sql_type: diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>,
40                <#sql_type as diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>>::Strategy: diesel::internal::derives::enum_::EnumMapping<__DB>,
41            {
42                fn from_sql(value: <__DB as diesel::backend::Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
43                    const VARIANTS: &[diesel::internal::derives::enum_::EnumVariant] = &[#(#variants,)*];
44                    let idx = <<#sql_type as diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>>::Strategy as diesel::internal::derives::enum_::EnumMapping<__DB>>::map_from_database_value(
45                        value,
46                        stringify!(#enum_name),
47                        VARIANTS
48                    )?;
49                    match idx {
50                        #(#variant_constructor,)*
51                        _ => unreachable!("We construct all relevant variants"),
52                    }
53                }
54            }
55        });
56
57        to_sql_impls.push({
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident(&mut _s, "impl");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "serialize");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "ToSql");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "for");
    ::quote::ToTokens::to_tokens(&enum_name, &mut _s);
    ::quote::__private::push_ident(&mut _s, "where");
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "backend");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Backend");
    ::quote::__private::push_comma(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&has_explicit_discriminant, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
    ::quote::__private::push_ident(&mut _s, "as");
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "sql_types");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
    ::quote::__private::push_lt(&mut _s);
    ::quote::ToTokens::to_tokens(&has_explicit_discriminant, &mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_shr(&mut _s);
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "Strategy");
    ::quote::__private::push_colon(&mut _s);
    ::quote::__private::push_ident(&mut _s, "diesel");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "internal");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "derives");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "enum_");
    ::quote::__private::push_colon2(&mut _s);
    ::quote::__private::push_ident(&mut _s, "EnumMapping");
    ::quote::__private::push_lt(&mut _s);
    ::quote::__private::push_ident(&mut _s, "__DB");
    ::quote::__private::push_gt(&mut _s);
    ::quote::__private::push_comma(&mut _s);
    ::quote::__private::push_group(&mut _s,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident(&mut _s, "fn");
            ::quote::__private::push_ident(&mut _s, "to_sql");
            ::quote::__private::push_lt(&mut _s);
            ::quote::__private::push_lifetime(&mut _s, "\'b");
            ::quote::__private::push_gt(&mut _s);
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_lifetime(&mut _s, "\'b");
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "output");
                    ::quote::__private::push_colon(&mut _s);
                    ::quote::__private::push_and(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "mut");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "serialize");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Output");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_lifetime(&mut _s, "\'b");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_lifetime(&mut _s, "\'_");
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_gt(&mut _s);
                    _s
                });
            ::quote::__private::push_rarrow(&mut _s);
            ::quote::__private::push_ident(&mut _s, "diesel");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "serialize");
            ::quote::__private::push_colon2(&mut _s);
            ::quote::__private::push_ident(&mut _s, "Result");
            ::quote::__private::push_group(&mut _s,
                ::quote::__private::Delimiter::Brace,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::__private::push_ident(&mut _s, "let");
                    ::quote::__private::push_ident(&mut _s, "variant");
                    ::quote::__private::push_eq(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "match");
                    ::quote::__private::push_ident(&mut _s, "self");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Brace,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            {
                                use ::quote::__private::ext::*;
                                let has_iter = ::quote::__private::HasIterator::<false>;
                                #[allow(unused_mut)]
                                let (mut variant_to_enum_variant_mapping, i) =
                                    variant_to_enum_variant_mapping.quote_into_iter();
                                let has_iter = has_iter | i;
                                <_ as
                                        ::quote::__private::CheckHasIterator<true>>::check(has_iter);
                                while true {
                                    let variant_to_enum_variant_mapping =
                                        match variant_to_enum_variant_mapping.next() {
                                            Some(_x) => ::quote::__private::RepInterp(_x),
                                            None => break,
                                        };
                                    ::quote::ToTokens::to_tokens(&variant_to_enum_variant_mapping,
                                        &mut _s);
                                    ::quote::__private::push_comma(&mut _s);
                                }
                            }
                            _s
                        });
                    ::quote::__private::push_semi(&mut _s);
                    ::quote::__private::push_shl(&mut _s);
                    ::quote::ToTokens::to_tokens(&sql_type, &mut _s);
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "sql_types");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "EnumSqlType");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::ToTokens::to_tokens(&has_explicit_discriminant,
                        &mut _s);
                    ::quote::__private::push_comma(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_shr(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "Strategy");
                    ::quote::__private::push_ident(&mut _s, "as");
                    ::quote::__private::push_ident(&mut _s, "diesel");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "internal");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "derives");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "enum_");
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "EnumMapping");
                    ::quote::__private::push_lt(&mut _s);
                    ::quote::__private::push_ident(&mut _s, "__DB");
                    ::quote::__private::push_shr(&mut _s);
                    ::quote::__private::push_colon2(&mut _s);
                    ::quote::__private::push_ident(&mut _s,
                        "map_to_database_value");
                    ::quote::__private::push_group(&mut _s,
                        ::quote::__private::Delimiter::Parenthesis,
                        {
                            let mut _s = ::quote::__private::TokenStream::new();
                            ::quote::__private::push_ident(&mut _s, "output");
                            ::quote::__private::push_comma(&mut _s);
                            ::quote::__private::push_ident(&mut _s, "variant");
                            _s
                        });
                    _s
                });
            _s
        });
    _s
}quote::quote! {
58            impl<__DB> diesel::serialize::ToSql<#sql_type, __DB> for #enum_name
59            where
60                __DB: diesel::backend::Backend,
61                #sql_type: diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>,
62                <#sql_type as diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>>::Strategy: diesel::internal::derives::enum_::EnumMapping<__DB>,
63            {
64                fn to_sql<'b>(&'b self, output: &mut diesel::serialize::Output<'b, '_, __DB>) -> diesel::serialize::Result {
65                    let variant = match self {
66                        #(#variant_to_enum_variant_mapping,)*
67                    };
68                    <<#sql_type as diesel::sql_types::EnumSqlType<#has_explicit_discriminant, __DB>>::Strategy as diesel::internal::derives::enum_::EnumMapping<__DB>>::map_to_database_value(
69                        output,
70                        variant
71                    )
72                }
73            }
74        });
75    }
76
77    let struct_ty = syn::Type::Path(syn::TypePath {
78        qself: None,
79        path: item.ident.into(),
80    });
81    let sql_types = item
82        .sql_type_attrs
83        .iter()
84        .map(|v| syn::Type::Path(v.item.clone()))
85        .collect::<Vec<_>>();
86    let as_expression_impl = super::as_expression::derive_inner(
87        sql_types,
88        syn::Generics::default(),
89        struct_ty.clone(),
90        false,
91        false,
92    )?;
93    let from_sql_row_impl = super::from_sql_row::derive_inner(struct_ty, syn::Generics::default())?;
94
95    Ok(wrap_in_dummy_mod({
    let mut _s = ::quote::__private::TokenStream::new();
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut from_sql_impls, i) = from_sql_impls.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let from_sql_impls =
                match from_sql_impls.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&from_sql_impls, &mut _s);
        }
    }
    {
        use ::quote::__private::ext::*;
        let has_iter = ::quote::__private::HasIterator::<false>;
        #[allow(unused_mut)]
        let (mut to_sql_impls, i) = to_sql_impls.quote_into_iter();
        let has_iter = has_iter | i;
        <_ as ::quote::__private::CheckHasIterator<true>>::check(has_iter);
        while true {
            let to_sql_impls =
                match to_sql_impls.next() {
                    Some(_x) => ::quote::__private::RepInterp(_x),
                    None => break,
                };
            ::quote::ToTokens::to_tokens(&to_sql_impls, &mut _s);
        }
    }
    ::quote::ToTokens::to_tokens(&as_expression_impl, &mut _s);
    ::quote::ToTokens::to_tokens(&from_sql_row_impl, &mut _s);
    _s
}quote::quote! {
96        #(#from_sql_impls)*
97        #(#to_sql_impls)*
98
99        #as_expression_impl
100        #from_sql_row_impl
101    }))
102}
103
104pub struct DeriveEnumInput {
105    sql_type_attrs: Vec<AttributeSpanWrapper<syn::TypePath>>,
106    ident: syn::Ident,
107    has_explicit_discriminants: bool,
108    variants: Vec<EnumVariant>,
109}
110
111pub struct EnumVariant {
112    span: Span,
113    discriminant: i128,
114    rust_name: Ident,
115    sql_name: String,
116}
117
118impl EnumVariant {
119    fn as_diesel_enum_variant(&self) -> TokenStream {
120        let Self {
121            span,
122            discriminant,
123            rust_name,
124            sql_name,
125        } = self;
126        let span = *span;
127        {
    let _span: ::quote::__private::Span =
        ::quote::__private::get_span(span).__into_span();
    let mut _s = ::quote::__private::TokenStream::new();
    ::quote::__private::push_ident_spanned(&mut _s, _span, "diesel");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "internal");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "derives");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "enum_");
    ::quote::__private::push_colon2_spanned(&mut _s, _span);
    ::quote::__private::push_ident_spanned(&mut _s, _span, "EnumVariant");
    ::quote::__private::push_group_spanned(&mut _s, _span,
        ::quote::__private::Delimiter::Brace,
        {
            let mut _s = ::quote::__private::TokenStream::new();
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "discriminant");
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&discriminant, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "rust_name");
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "stringify");
            ::quote::__private::push_bang_spanned(&mut _s, _span);
            ::quote::__private::push_group_spanned(&mut _s, _span,
                ::quote::__private::Delimiter::Parenthesis,
                {
                    let mut _s = ::quote::__private::TokenStream::new();
                    ::quote::ToTokens::to_tokens(&rust_name, &mut _s);
                    _s
                });
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            ::quote::__private::push_ident_spanned(&mut _s, _span,
                "sql_name");
            ::quote::__private::push_colon_spanned(&mut _s, _span);
            ::quote::ToTokens::to_tokens(&sql_name, &mut _s);
            ::quote::__private::push_comma_spanned(&mut _s, _span);
            _s
        });
    _s
}quote::quote_spanned! {span=>
128                diesel::internal::derives::enum_::EnumVariant {
129                    discriminant: #discriminant,
130                    rust_name: stringify!(#rust_name),
131                    sql_name: #sql_name,
132                }
133        }
134    }
135}
136
137impl syn::parse::Parse for DeriveEnumInput {
138    fn parse(input: syn::parse::ParseStream) -> Result<Self> {
139        let input = input.parse::<syn::DeriveInput>()?;
140        let input_span = input.span();
141        if !input.generics.params.is_empty() {
142            return Err(syn::Error::new(input.span(), ERROR_MESSAGE));
143        }
144        let enum_ = match input.data {
145            Data::Enum(data_enum) => data_enum,
146            _ => {
147                return Err(syn::Error::new(input.span(), ERROR_MESSAGE));
148            }
149        };
150        let attrs = crate::attrs::parse_attributes::<crate::attrs::StructAttr>(&input.attrs)?;
151        let rename_all = attrs.iter().find_map(|a| {
152            if let crate::attrs::StructAttr::RenameAll(_, r) = &a.item {
153                Some(r)
154            } else {
155                None
156            }
157        });
158
159        let mut has_explicit_discriminants = true;
160        let mut variants = Vec::with_capacity(enum_.variants.len());
161        for (idx, v) in enum_.variants.iter().enumerate() {
162            if !v.fields.is_empty() {
163                return Err(syn::Error::new(v.span(), ERROR_MESSAGE));
164            }
165            has_explicit_discriminants = has_explicit_discriminants && v.discriminant.is_some();
166            let discriminant = v
167                .discriminant
168                .as_ref()
169                .map(|(_, v)| {
170                    let (f, l) = match v {
171                        syn::Expr::Lit(l) => (1, l),
172                        syn::Expr::Unary(syn::ExprUnary {
173                            op: syn::UnOp::Neg(_),
174                            expr,
175                            ..
176                        }) => {
177                            if let syn::Expr::Lit(l) = &**expr {
178                                (-1, l)
179                            } else {
180                                return Err(syn::Error::new(
181                                    v.span(),
182                                    "expected a literal expression, but got something else",
183                                ));
184                            }
185                        }
186                        _ => {
187                            return Err(syn::Error::new(
188                                v.span(),
189                                "expected a literal expression, but got something else",
190                            ));
191                        }
192                    };
193                    let syn::Lit::Int(i) = &l.lit else {
194                        return Err(syn::Error::new(
195                            l.span(),
196                            "expected a integer literal expression, but got something else",
197                        ));
198                    };
199                    Ok(f * i.base10_parse::<i128>()?)
200                })
201                .transpose()?
202                .unwrap_or(idx as i128);
203            let rust_name = v.ident.clone();
204            let attrs = crate::attrs::parse_attributes::<crate::attrs::FieldAttr>(&v.attrs)?;
205            let rename_attr = attrs.iter().find_map(|a| {
206                if let crate::attrs::FieldAttr::Rename(_, r) = &a.item {
207                    Some(r.value())
208                } else {
209                    None
210                }
211            });
212            let sql_name = rename_attr
213                .or_else(|| Some(rename_all?.apply_case_to_enum_variant(rust_name.to_string())))
214                .unwrap_or_else(|| rust_name.to_string());
215            variants.push(EnumVariant {
216                span: v.span(),
217                discriminant,
218                rust_name,
219                sql_name,
220            });
221        }
222
223        let sql_type_attrs = attrs
224            .into_iter()
225            .filter_map(|a: AttributeSpanWrapper<crate::attrs::StructAttr>| {
226                if let crate::attrs::StructAttr::SqlType(_, path) = a.item {
227                    Some(crate::attrs::AttributeSpanWrapper {
228                        item: path,
229                        attribute_span: a.attribute_span,
230                        ident_span: a.ident_span,
231                    })
232                } else {
233                    None
234                }
235            })
236            .collect::<Vec<_>>();
237        if sql_type_attrs.is_empty() {
238            return Err(syn::Error::new(
239                input_span,
240                "no `#[diesel(sql_type = ...)]` attribute provided",
241            ));
242        }
243
244        Ok(Self {
245            sql_type_attrs,
246            ident: input.ident,
247            has_explicit_discriminants,
248            variants,
249        })
250    }
251}