Skip to main content

rusqlite_struct_derive/
lib.rs

1extern 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    // The name of the struct.
12    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            // Fail if Serialize and Deserialize are not derived.
34            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}