Skip to main content

diesel_derives/
enum_.rs

1use diesel_attribute_parser::AttributeSpanWrapper;
2use proc_macro2::{Span, TokenStream};
3use syn::{Data, Ident, Result, spanned::Spanned};
4
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        attrs: Vec::new(),
81    });
82    let sql_types = item
83        .sql_type_attrs
84        .iter()
85        .map(|v| syn::Type::Path(v.item.clone()))
86        .collect::<Vec<_>>();
87    let as_expression_impl = super::as_expression::derive_inner(
88        sql_types,
89        syn::Generics::default(),
90        struct_ty.clone(),
91        false,
92        false,
93    )?;
94    let from_sql_row_impl = super::from_sql_row::derive_inner(struct_ty, syn::Generics::default())?;
95
96    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! {
97        #(#from_sql_impls)*
98        #(#to_sql_impls)*
99
100        #as_expression_impl
101        #from_sql_row_impl
102    }))
103}
104
105pub struct DeriveEnumInput {
106    sql_type_attrs: Vec<AttributeSpanWrapper<syn::TypePath>>,
107    ident: syn::Ident,
108    has_explicit_discriminants: bool,
109    variants: Vec<EnumVariant>,
110}
111
112pub struct EnumVariant {
113    span: Span,
114    discriminant: i128,
115    rust_name: Ident,
116    sql_name: String,
117}
118
119impl EnumVariant {
120    fn as_diesel_enum_variant(&self) -> TokenStream {
121        let Self {
122            span,
123            discriminant,
124            rust_name,
125            sql_name,
126        } = self;
127        let span = *span;
128        {
    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=>
129                diesel::internal::derives::enum_::EnumVariant {
130                    discriminant: #discriminant,
131                    rust_name: stringify!(#rust_name),
132                    sql_name: #sql_name,
133                }
134        }
135    }
136}
137
138impl syn::parse::Parse for DeriveEnumInput {
139    fn parse(input: syn::parse::ParseStream) -> Result<Self> {
140        let input = input.parse::<syn::DeriveInput>()?;
141        let input_span = input.span();
142        if !input.generics.params.is_empty() {
143            return Err(syn::Error::new(input.span(), ERROR_MESSAGE));
144        }
145        let enum_ = match input.data {
146            Data::Enum(data_enum) => data_enum,
147            _ => {
148                return Err(syn::Error::new(input.span(), ERROR_MESSAGE));
149            }
150        };
151        let attrs = diesel_attribute_parser::parse_attributes::<diesel_attribute_parser::StructAttr>(
152            &input.attrs,
153        )?;
154        let rename_all = attrs.iter().find_map(|a| {
155            if let diesel_attribute_parser::StructAttr::RenameAll(_, r) = &a.item {
156                Some(r)
157            } else {
158                None
159            }
160        });
161
162        let mut has_explicit_discriminants = true;
163        let mut variants = Vec::with_capacity(enum_.variants.len());
164        for (idx, v) in enum_.variants.iter().enumerate() {
165            if !v.fields.is_empty() {
166                return Err(syn::Error::new(v.span(), ERROR_MESSAGE));
167            }
168            has_explicit_discriminants = has_explicit_discriminants && v.discriminant.is_some();
169            let discriminant = v
170                .discriminant
171                .as_ref()
172                .map(|(_, v)| {
173                    let (f, l) = match v {
174                        syn::Expr::Lit(l) => (1, l),
175                        syn::Expr::Unary(syn::ExprUnary {
176                            op: syn::UnOp::Neg(_),
177                            expr,
178                            ..
179                        }) => {
180                            if let syn::Expr::Lit(l) = &**expr {
181                                (-1, l)
182                            } else {
183                                return Err(syn::Error::new(
184                                    v.span(),
185                                    "expected a literal expression, but got something else",
186                                ));
187                            }
188                        }
189                        _ => {
190                            return Err(syn::Error::new(
191                                v.span(),
192                                "expected a literal expression, but got something else",
193                            ));
194                        }
195                    };
196                    let syn::Lit::Int(i) = &l.lit else {
197                        return Err(syn::Error::new(
198                            l.span(),
199                            "expected a integer literal expression, but got something else",
200                        ));
201                    };
202                    Ok(f * i.base10_parse::<i128>()?)
203                })
204                .transpose()?
205                .unwrap_or(idx as i128);
206            let rust_name = v.ident.clone();
207            let attrs = diesel_attribute_parser::parse_attributes::<
208                diesel_attribute_parser::FieldAttr,
209            >(&v.attrs)?;
210            let rename_attr = attrs.iter().find_map(|a| {
211                if let diesel_attribute_parser::FieldAttr::Rename(_, r) = &a.item {
212                    Some(r.value())
213                } else {
214                    None
215                }
216            });
217            let sql_name = rename_attr
218                .or_else(|| Some(rename_all?.apply_case_to_enum_variant(rust_name.to_string())))
219                .unwrap_or_else(|| rust_name.to_string());
220            variants.push(EnumVariant {
221                span: v.span(),
222                discriminant,
223                rust_name,
224                sql_name,
225            });
226        }
227
228        let sql_type_attrs = attrs
229            .into_iter()
230            .filter_map(
231                |a: AttributeSpanWrapper<diesel_attribute_parser::StructAttr>| {
232                    if let diesel_attribute_parser::StructAttr::SqlType(_, path) = a.item {
233                        Some(diesel_attribute_parser::AttributeSpanWrapper {
234                            item: path,
235                            attribute_span: a.attribute_span,
236                            ident_span: a.ident_span,
237                        })
238                    } else {
239                        None
240                    }
241                },
242            )
243            .collect::<Vec<_>>();
244        if sql_type_attrs.is_empty() {
245            return Err(syn::Error::new(
246                input_span,
247                "no `#[diesel(sql_type = ...)]` attribute provided",
248            ));
249        }
250
251        Ok(Self {
252            sql_type_attrs,
253            ident: input.ident,
254            has_explicit_discriminants,
255            variants,
256        })
257    }
258}