extern crate proc_macro;
extern crate syn;
#[macro_use]
extern crate quote;
extern crate proc_macro2;
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use syn::{DataStruct, DeriveInput, Meta};
mod generate;
use crate::generate::{GenMode, GenParams};
#[proc_macro_derive(Getters, attributes(get, with_prefix))]
pub fn getters(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters");
let params = GenParams {
attribute_name: "get",
fn_name_prefix: "",
fn_name_suffix: "",
global_attr: parse_global_attr(&ast.attrs, "get"),
};
let gen = produce(&ast, &GenMode::Get, ¶ms);
gen.into()
}
#[proc_macro_derive(CopyGetters, attributes(get_copy, with_prefix))]
pub fn copy_getters(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters");
let params = GenParams {
attribute_name: "get_copy",
fn_name_prefix: "",
fn_name_suffix: "",
global_attr: parse_global_attr(&ast.attrs, "get_copy"),
};
let gen = produce(&ast, &GenMode::GetCopy, ¶ms);
gen.into()
}
#[proc_macro_derive(MutGetters, attributes(get_mut))]
pub fn mut_getters(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for getters");
let params = GenParams {
attribute_name: "get_mut",
fn_name_prefix: "",
fn_name_suffix: "_mut",
global_attr: parse_global_attr(&ast.attrs, "get_mut"),
};
let gen = produce(&ast, &GenMode::GetMut, ¶ms);
gen.into()
}
#[proc_macro_derive(Setters, attributes(set))]
pub fn setters(input: TokenStream) -> TokenStream {
let ast: DeriveInput = syn::parse(input).expect("Couldn't parse for setters");
let params = GenParams {
attribute_name: "set",
fn_name_prefix: "set_",
fn_name_suffix: "",
global_attr: parse_global_attr(&ast.attrs, "set"),
};
let gen = produce(&ast, &GenMode::Set, ¶ms);
gen.into()
}
fn parse_global_attr(attrs: &[syn::Attribute], attribute_name: &str) -> Option<Meta> {
attrs
.iter()
.filter_map(|v| {
let meta = v.parse_meta().expect("attribute");
if meta.path().is_ident(attribute_name) {
Some(meta)
} else {
None
}
})
.last()
}
fn produce(ast: &DeriveInput, mode: &GenMode, params: &GenParams) -> TokenStream2 {
let name = &ast.ident;
let generics = &ast.generics;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
if let syn::Data::Struct(DataStruct { ref fields, .. }) = ast.data {
let generated = fields
.iter()
.map(|f| generate::implement(f, mode, params))
.collect::<Vec<_>>();
quote! {
impl #impl_generics #name #ty_generics #where_clause {
#(#generated)*
}
}
} else {
panic!("#[derive(Getters)] is only defined for structs, not for enums!");
}
}