| use synstructure; |
| use syn::{self, Meta, NestedMeta, parse_quote}; |
| use proc_macro2::{self, Ident}; |
| use quote::quote; |
| |
| struct Attributes { |
| ignore: bool, |
| project: Option<Ident>, |
| } |
| |
| fn parse_attributes(field: &syn::Field) -> Attributes { |
| let mut attrs = Attributes { |
| ignore: false, |
| project: None, |
| }; |
| for attr in &field.attrs { |
| if let Ok(meta) = attr.parse_meta() { |
| if &meta.name().to_string() != "stable_hasher" { |
| continue; |
| } |
| let mut any_attr = false; |
| if let Meta::List(list) = meta { |
| for nested in list.nested.iter() { |
| if let NestedMeta::Meta(meta) = nested { |
| if &meta.name().to_string() == "ignore" { |
| attrs.ignore = true; |
| any_attr = true; |
| } |
| if &meta.name().to_string() == "project" { |
| if let Meta::List(list) = meta { |
| if let Some(nested) = list.nested.iter().next() { |
| if let NestedMeta::Meta(meta) = nested { |
| attrs.project = Some(meta.name()); |
| any_attr = true; |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| if !any_attr { |
| panic!("error parsing stable_hasher"); |
| } |
| } |
| } |
| attrs |
| } |
| |
| pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { |
| let generic: syn::GenericParam = parse_quote!('__ctx); |
| s.add_bounds(synstructure::AddBounds::Generics); |
| s.add_impl_generic(generic); |
| let body = s.each(|bi| { |
| let attrs = parse_attributes(bi.ast()); |
| if attrs.ignore { |
| quote!{} |
| } else if let Some(project) = attrs.project { |
| quote!{ |
| &#bi.#project.hash_stable(__hcx, __hasher); |
| } |
| } else { |
| quote!{ |
| #bi.hash_stable(__hcx, __hasher); |
| } |
| } |
| }); |
| |
| let discriminant = match s.ast().data { |
| syn::Data::Enum(_) => quote! { |
| ::std::mem::discriminant(self).hash_stable(__hcx, __hasher); |
| }, |
| syn::Data::Struct(_) => quote! {}, |
| syn::Data::Union(_) => panic!("cannot derive on union"), |
| }; |
| |
| s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable |
| <::rustc::ich::StableHashingContext<'__ctx>>), quote!{ |
| fn hash_stable<__W: ::rustc_data_structures::stable_hasher::StableHasherResult>( |
| &self, |
| __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>, |
| __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher<__W>) { |
| #discriminant |
| match *self { #body } |
| } |
| }) |
| } |