use std::collections::HashSet;
use quote::ToTokens;
use roxygen::roxygen;
use syn::Item;
use crate::api::record::SourceLocation;
pub struct Builder {
derive_attrs: HashSet<String>,
}
impl Builder {
pub fn new() -> Self {
Self {
derive_attrs: HashSet::new(),
}
}
#[roxygen]
pub fn strip_derive<S: Into<String>>(
mut self,
derive: S,
) -> Self {
self.derive_attrs.insert(derive.into());
self
}
pub fn build(self) -> StripDerives {
StripDerives { builder: self }
}
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
pub struct StripDerives {
builder: Builder,
}
impl StripDerives {
pub fn builder() -> Builder {
Builder::new()
}
pub fn call(&self, item: (Item, SourceLocation)) -> (Item, SourceLocation) {
let (mut item, source_location) = item;
match &mut item {
Item::Struct(s) => {
self.strip_derives_from_attrs(&mut s.attrs);
}
Item::Enum(e) => {
self.strip_derives_from_attrs(&mut e.attrs);
}
_ => {}
}
(item, source_location)
}
fn strip_derives_from_attrs(&self, attrs: &mut Vec<syn::Attribute>) {
for attr in attrs.iter_mut() {
if attr.path().is_ident("derive") {
if let Ok(list) = attr.parse_args_with(
syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated,
) {
let filtered: syn::punctuated::Punctuated<syn::Path, syn::Token![,]> = list
.into_iter()
.filter(|path| {
!self
.builder
.derive_attrs
.contains(&path.get_ident().unwrap().to_string())
})
.collect();
attr.meta = syn::Meta::List(syn::MetaList {
path: attr.path().clone(),
delimiter: syn::MacroDelimiter::Paren(Default::default()),
tokens: filtered.to_token_stream(),
});
}
}
}
attrs.retain(|attr| {
!attr.path().is_ident("derive")
|| attr
.parse_args_with(
syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated,
)
.map_or(
true,
|list: syn::punctuated::Punctuated<syn::Path, syn::Token![,]>| {
!list.is_empty()
},
)
});
}
pub fn into_closure(self) -> impl FnMut((Item, SourceLocation)) -> (Item, SourceLocation) {
move |item| self.call(item)
}
}