mirror of
				https://github.com/rust-lang/rust.git
				synced 2025-10-31 13:04:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			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 }
 | |
|             }
 | |
|         }
 | |
|     })
 | |
| }
 | 
