extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Data, Fields};
#[proc_macro_derive(RusqliteStruct)]
pub fn rusqlite_struct(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = input.ident;
let field_names: Vec<String> = match input.data {
Data::Struct(ref data_struct) => match &data_struct.fields {
Fields::Named(fields_named) => fields_named
.named
.iter()
.map(|f| f.ident.as_ref().unwrap().to_string())
.collect(),
_ => panic!("RusqliteStruct only supports structs with named fields."),
},
_ => panic!("RustqliteStruct can only be derived for structs."),
};
let field_names_lit: Vec<proc_macro2::TokenStream> = field_names
.iter()
.map(|f| quote! { #f })
.collect();
let expanded = quote! {
const _: () = {
trait _Check: serde::Serialize + for<'de> serde::Deserialize<'de> {}
impl _Check for #name {}
};
impl rusqlite_struct::RusqliteStruct for #name {
pub fn struct_name() -> &'static str {
stringify!(#name);
}
pub fn field_names() -> &'static [&'static str] {
&[#(#field_names_lit),*]
}
}
};
TokenStream::from(expanded)
}