1mod utils;
2
3extern crate proc_macro;
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{parse_macro_input, DeriveInput, Ident};
8
9#[proc_macro_derive(Fields, attributes(field))]
10pub fn derives_fields(input: TokenStream) -> TokenStream {
11 let ast = parse_macro_input!(input as DeriveInput);
12 let struct_name = ast.ident;
13
14 let fields = if let syn::Data::Struct(syn::DataStruct {
16 fields: syn::Fields::Named(ref fields),
17 ..
18 }) = ast.data
19 {
20 fields
21 } else {
22 panic!("Only support Struct")
23 };
24
25 let props = utils::get_props(fields);
27
28 let props_all_idents: Vec<&Option<Ident>> = props.iter().map(|p| p.ident).collect();
29 let props_all_names: Vec<&String> = props.iter().map(|p| &p.name).collect();
30
31 let props_option_idents: Vec<&Option<Ident>> = props.iter().filter(|p| p.is_option).map(|p| p.ident).collect();
32 let props_option_names: Vec<&String> = props.iter().filter(|p| p.is_option).map(|p| &p.name).collect();
33
34 let props_not_option_idents: Vec<&Option<Ident>> = props.iter().filter(|p| !p.is_option).map(|p| p.ident).collect();
35 let props_not_option_names: Vec<&String> = props.iter().filter(|p| !p.is_option).map(|p| &p.name).collect();
36
37 let ff_all_pushes = quote! {
39 #(
40 ff.push((#props_all_names, self.#props_all_idents).into());
41 )*
42 };
43
44 let ff_not_option_pushes = quote! {
45 #(
46 ff.push((#props_not_option_names, self.#props_not_option_idents).into());
47 )*
48 };
49
50 let ff_option_not_none_pushes = quote! {
51 #(
52 if let Some(val) = self.#props_option_idents {
53 ff.push((#props_option_names, val).into());
54 }
55 )*
56 };
57
58 let output = quote! {
60 impl sqlb::HasFields for #struct_name {
61
62 fn not_none_fields<'a>( self) -> Vec<sqlb::Field<'a>> {
63 let mut ff: Vec<sqlb::Field> = Vec::new();
64 #ff_not_option_pushes
65 #ff_option_not_none_pushes
66 ff
67 }
68
69 fn all_fields<'a>( self) -> Vec<sqlb::Field<'a>> {
70 let mut ff: Vec<sqlb::Field> = Vec::new();
71 #ff_all_pushes
72 ff
73 }
74
75 fn field_names() -> &'static [&'static str] {
76 &[#(
77 #props_all_names,
78 )*]
79 }
80 }
81 };
82
83 output.into()
84}