sqlb_macros/
lib.rs

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	// -- get the fields
15	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	// -- Collect Elements
26	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	// -- Vec push code for the (name, value)
38	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	// -- Compose the final code
59	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}