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}