rusqlite_struct_derive/
lib.rs1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{parse_macro_input, DeriveInput, Data, Fields};
6
7#[proc_macro_derive(RusqliteStruct)]
8pub fn rusqlite_struct(input: TokenStream) -> TokenStream {
9 let input = parse_macro_input!(input as DeriveInput);
10
11 let name = input.ident;
13
14 let field_names: Vec<String> = match input.data {
15 Data::Struct(ref data_struct) => match &data_struct.fields {
16 Fields::Named(fields_named) => fields_named
17 .named
18 .iter()
19 .map(|f| f.ident.as_ref().unwrap().to_string())
20 .collect(),
21 _ => panic!("RusqliteStruct only supports structs with named fields."),
22 },
23 _ => panic!("RustqliteStruct can only be derived for structs."),
24 };
25
26 let field_names_lit: Vec<proc_macro2::TokenStream> = field_names
27 .iter()
28 .map(|f| quote! { #f })
29 .collect();
30
31 let expanded = quote! {
32 const _: () = {
33 trait _Check: serde::Serialize + for<'de> serde::Deserialize<'de> {}
35 impl _Check for #name {}
36 };
37
38 impl rusqlite_struct::RusqliteStruct for #name {
39 fn struct_name() -> &'static str {
40 stringify!(#name)
41 }
42
43 fn field_names() -> &'static [&'static str] {
44 &[#(#field_names_lit),*]
45 }
46 }
47 };
48
49 TokenStream::from(expanded)
50}