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}