use proc_macro2; use ast; use attr; use matcher; use paths; use syn; use utils; pub fn derive(input: &ast::Input) -> proc_macro2::TokenStream { let hasher_trait_path = hasher_trait_path(); let hash_trait_path = hash_trait_path(); let discriminant = if let ast::Body::Enum(_) = input.body { let discriminant = paths::discriminant_path(); Some(quote!( #hash_trait_path::hash(&#discriminant(self), __state); )) } else { None }; let body = matcher::Matcher::new(matcher::BindingStyle::Ref, input.attrs.is_packed).build_arms( input, "__arg", |_, _, _, _, _, bis| { let field_prints = bis.iter().filter_map(|bi| { if bi.field.attrs.ignore_hash() { return None; } let arg = &bi.expr; if let Some(hash_with) = bi.field.attrs.hash_with() { Some(quote! { #hash_with(&#arg, __state); }) } else { Some(quote! { #hash_trait_path::hash(&#arg, __state); }) } }); quote! { #(#field_prints)* } }, ); let name = &input.ident; let generics = utils::build_impl_generics( input, &hash_trait_path, needs_hash_bound, |field| field.hash_bound(), |input| input.hash_bound(), ); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let hasher_ty_parameter = utils::hygienic_type_parameter(input, "__H"); quote! { #[allow(unused_qualifications)] impl #impl_generics #hash_trait_path for #name #ty_generics #where_clause { fn hash<#hasher_ty_parameter>(&self, __state: &mut #hasher_ty_parameter) where #hasher_ty_parameter: #hasher_trait_path { #discriminant match *self { #body } } } } } fn needs_hash_bound(attrs: &attr::Field) -> bool { !attrs.ignore_hash() && attrs.hash_bound().is_none() } /// Return the path of the `Hash` trait, that is `::std::hash::Hash`. fn hash_trait_path() -> syn::Path { if cfg!(feature = "use_core") { parse_quote!(::core::hash::Hash) } else { parse_quote!(::std::hash::Hash) } } /// Return the path of the `Hasher` trait, that is `::std::hash::Hasher`. fn hasher_trait_path() -> syn::Path { if cfg!(feature = "use_core") { parse_quote!(::core::hash::Hasher) } else { parse_quote!(::std::hash::Hasher) } }