83 lines
2.6 KiB
Rust
83 lines
2.6 KiB
Rust
|
|
use quote::quote;
|
||
|
|
use synstructure::BindingInfo;
|
||
|
|
|
||
|
|
pub(super) fn visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
|
||
|
|
if let syn::Data::Union(_) = s.ast().data {
|
||
|
|
panic!("cannot derive on union")
|
||
|
|
}
|
||
|
|
|
||
|
|
let has_attr = |bind: &BindingInfo<'_>, name| {
|
||
|
|
let mut found = false;
|
||
|
|
bind.ast().attrs.iter().for_each(|attr| {
|
||
|
|
if !attr.path().is_ident("visitable") {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let _ = attr.parse_nested_meta(|nested| {
|
||
|
|
if nested.path.is_ident(name) {
|
||
|
|
found = true;
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
});
|
||
|
|
});
|
||
|
|
found
|
||
|
|
};
|
||
|
|
|
||
|
|
let get_attr = |bind: &BindingInfo<'_>, name: &str| {
|
||
|
|
let mut content = None;
|
||
|
|
bind.ast().attrs.iter().for_each(|attr| {
|
||
|
|
if !attr.path().is_ident("visitable") {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
let _ = attr.parse_nested_meta(|nested| {
|
||
|
|
if nested.path.is_ident(name) {
|
||
|
|
let value = nested.value()?;
|
||
|
|
let value = value.parse()?;
|
||
|
|
content = Some(value);
|
||
|
|
}
|
||
|
|
Ok(())
|
||
|
|
});
|
||
|
|
});
|
||
|
|
content
|
||
|
|
};
|
||
|
|
|
||
|
|
s.add_bounds(synstructure::AddBounds::Generics);
|
||
|
|
s.bind_with(|_| synstructure::BindStyle::Ref);
|
||
|
|
let ref_visit = s.each(|bind| {
|
||
|
|
let extra = get_attr(bind, "extra").unwrap_or(quote! {});
|
||
|
|
if has_attr(bind, "ignore") {
|
||
|
|
quote! {}
|
||
|
|
} else {
|
||
|
|
quote! { rustc_ast_ir::try_visit!(crate::visit::Visitable::visit(#bind, __visitor, (#extra))) }
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
s.bind_with(|_| synstructure::BindStyle::RefMut);
|
||
|
|
let mut_visit = s.each(|bind| {
|
||
|
|
let extra = get_attr(bind, "extra").unwrap_or(quote! {});
|
||
|
|
if has_attr(bind, "ignore") {
|
||
|
|
quote! {}
|
||
|
|
} else {
|
||
|
|
quote! { crate::mut_visit::MutVisitable::visit_mut(#bind, __visitor, (#extra)) }
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
s.gen_impl(quote! {
|
||
|
|
gen impl<'__ast, __V> crate::visit::Walkable<'__ast, __V> for @Self
|
||
|
|
where __V: crate::visit::Visitor<'__ast>,
|
||
|
|
{
|
||
|
|
fn walk_ref(&'__ast self, __visitor: &mut __V) -> __V::Result {
|
||
|
|
match *self { #ref_visit }
|
||
|
|
<__V::Result as rustc_ast_ir::visit::VisitorResult>::output()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
gen impl<__V> crate::mut_visit::MutWalkable<__V> for @Self
|
||
|
|
where __V: crate::mut_visit::MutVisitor,
|
||
|
|
{
|
||
|
|
fn walk_mut(&mut self, __visitor: &mut __V) {
|
||
|
|
match *self { #mut_visit }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|