1use convert_case::{Case, Casing};
2use proc_macro::TokenStream;
3use syn::{parse_macro_input, spanned::Spanned, Data, DataStruct, DeriveInput, Fields, Ident};
4
5extern crate proc_macro;
6
7#[macro_use]
8extern crate quote;
9extern crate syn;
10
11#[proc_macro_attribute]
12pub fn auto_iden(_args: TokenStream, input: TokenStream) -> TokenStream {
13 let input = parse_macro_input!(input as DeriveInput);
14 let fields = match &input.data {
15 Data::Struct(DataStruct {
16 fields: Fields::Named(fields),
17 ..
18 }) => &fields.named,
19 _ => panic!("#[auto_iden] can only be used on structs"),
20 };
21 let field_names = fields.iter().map(|field| {
22 let ident = &field.ident;
23 let str = ident
24 .as_ref()
25 .expect("#[auto_iden] can only be used on structs with named fields")
26 .to_string();
27 let to_pascal = str.to_case(Case::Pascal);
28 (ident.as_ref().unwrap(), Ident::new(to_pascal.as_str(), ident.span()))
29 });
30 let table_name = input.ident.to_string().to_case(Case::Snake);
31 let struct_name = quote::format_ident!("{}TypeDef", &input.ident);
32 let pascal_names = field_names.clone().map(|(_, pascal)| pascal);
33 let snake_names = field_names.map(|(snake, _)| snake);
34 let pascal_names2 = pascal_names.clone();
35
36 TokenStream::from(quote! {
37 #input
38
39 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40 enum #struct_name {
41 Table,
42 #(#pascal_names),*
43 }
44
45 impl sea_query::Iden for #struct_name {
46 fn unquoted(&self, s: &mut dyn sea_query::Write) {
47 write!(s, "{}", match self {
48 #struct_name::Table => #table_name,
49 #(#struct_name::#pascal_names2 => stringify!(#snake_names)),*
50 }).unwrap();
51 }
52 }
53 })
54}