use std::collections::HashSet;
use roxygen::roxygen;
use syn::Item;
use crate::api::record::SourceLocation;
pub struct Builder {
macro_attrs: HashSet<String>,
}
impl Builder {
pub fn new() -> Self {
Self {
macro_attrs: HashSet::new(),
}
}
#[roxygen]
pub fn strip_macro<S: Into<String>>(
mut self,
macro_name: S,
) -> Self {
self.macro_attrs.insert(macro_name.into());
self
}
pub fn build(self) -> StripMacros {
StripMacros { builder: self }
}
}
impl Default for Builder {
fn default() -> Self {
Self::new()
}
}
pub struct StripMacros {
builder: Builder,
}
impl StripMacros {
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_macros_from_attrs(&mut s.attrs);
}
Item::Enum(e) => {
self.strip_macros_from_attrs(&mut e.attrs);
for variant in &mut e.variants {
self.strip_macros_from_attrs(&mut variant.attrs);
}
}
Item::Fn(f) => {
self.strip_macros_from_attrs(&mut f.attrs);
}
_ => {}
}
(item, source_location)
}
fn strip_macros_from_attrs(&self, attrs: &mut Vec<syn::Attribute>) {
attrs.retain(|attr| {
if let Some(ident) = attr.path().get_ident() {
!self.builder.macro_attrs.contains(&ident.to_string())
} else {
!attr.path().segments.iter().any(|segment| {
self.builder
.macro_attrs
.contains(&segment.ident.to_string())
})
}
});
}
pub fn into_closure(self) -> impl FnMut((Item, SourceLocation)) -> (Item, SourceLocation) {
move |item| self.call(item)
}
}