extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{Expr, ExprLit, ExprTuple, Lit, Token, parse_macro_input, punctuated::Punctuated};
#[proc_macro_derive(FieldNames)]
pub fn derive_field_names(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::ItemStruct);
let name = &input.ident;
let generics = &input.generics; let where_clause = &generics.where_clause;
let field_names: Vec<String> = input
.fields
.iter()
.map(|field| field.ident.clone().unwrap().to_string())
.collect();
quote! {
impl #generics #name #generics #where_clause {
pub fn get_field_names() -> std::collections::HashSet<String> {
[#(#field_names),*].iter().map(ToString::to_string).map(|s| s.replace("r#", "")).collect::<std::collections::HashSet<String>>()
}
}
}.into()
}
#[cfg(feature = "docs")]
#[proc_macro_derive(DocJsonSchema)]
pub fn derive_doc_json_schema(input: TokenStream) -> TokenStream {
let input = syn::parse_macro_input!(input as syn::ItemStruct);
let name = &input.ident;
quote! {
impl #name {
pub fn get_json_schema() -> schemars::schema::RootSchema {
let settings = schemars::r#gen::SchemaSettings::default().with(|s| {
s.inline_subschemas = true;
});
let generator = settings.into_generator();
generator.into_root_schema_for::<#name>()
}
}
}
.into()
}
#[cfg(not(doctest))]
#[proc_macro]
pub fn generate_lookup_functions(input: TokenStream) -> TokenStream {
let tuples =
parse_macro_input!(input with Punctuated::<ExprTuple, Token![,]>::parse_terminated);
let mut add_functions = Vec::new();
let mut lookup_names = Vec::new();
for tuple in tuples.iter() {
if let (
Some(Expr::Path(path)),
Some(Expr::Lit(ExprLit {
lit: Lit::Bool(lit_bool),
..
})),
) = (tuple.elems.first(), tuple.elems.last())
{
let func_name = path.path.segments.first().unwrap().ident.to_string(); lookup_names.push(func_name.clone());
if lit_bool.value {
add_functions.push(quote! {
#[cfg(feature = #func_name)]
env.add_function(#func_name, #path::function);
});
} else {
add_functions.push(quote! {
env.add_function(#func_name, #path::function);
});
}
}
}
quote! {
pub fn add_lookup_functions(env: &mut minijinja::Environment<'static>) {
#(#add_functions)*
}
#[cfg(feature = "docs")]
pub const LOOKUPS: &[&str] = &[
#(#lookup_names),*
];
}
.into()
}