squtils/
lib.rs

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}