use proc_macro::TokenStream;
use quote::quote;
use syn::{
Attribute, DeriveInput, ImplItem, ItemImpl, ItemStruct, Visibility, parse_macro_input,
token::Pub,
};
#[proc_macro_derive(PubSkip, attributes(skip))]
pub fn pub_skip(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as DeriveInput);
let name = &input.ident;
match &input.data {
syn::Data::Struct(_) => {}
_ => panic!("PubSkip only works on structs"),
}
TokenStream::from(quote! {
impl #name {}
})
}
#[proc_macro_attribute]
pub fn pub_struct(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut input = parse_macro_input!(item as ItemStruct);
input.vis = Visibility::Public(Pub::default());
for field in input.fields.iter_mut() {
if !has_skip(&mut field.attrs) {
field.vis = Visibility::Public(Pub::default());
}
}
TokenStream::from(quote! { #input })
}
#[proc_macro_attribute]
pub fn pub_methods(_attr: TokenStream, item: TokenStream) -> TokenStream {
let mut impl_block = parse_macro_input!(item as ItemImpl);
for item in &mut impl_block.items {
if let ImplItem::Fn(method) = item
&& !has_skip(&mut method.attrs)
{
method.vis = Visibility::Public(Pub::default());
}
}
TokenStream::from(quote! { #impl_block })
}
#[proc_macro_attribute]
pub fn skip(_attr: TokenStream, item: TokenStream) -> TokenStream {
item
}
fn has_skip(attrs: &mut Vec<Attribute>) -> bool {
let mut field_has_skip: bool = false;
attrs.retain(|attr| {
if attr.path().is_ident("skip") {
field_has_skip = true;
return false;
}
true
});
field_has_skip
}