1use proc_macro::TokenStream;
2use proc_macro2::Span;
3use syn;
4use quote::quote;
5
6#[proc_macro_derive(Hashable)]
7pub fn hashable_derive(input: TokenStream) -> TokenStream {
8 let ast: syn::DeriveInput = syn::parse(input).unwrap();
9
10 let name = &ast.ident;
11 let fields = match &ast.data {
12 syn::Data::Struct(syn::DataStruct {
13 fields: syn::Fields::Named(fields),
14 ..
15 }) => {
16 &fields.named
17 },
18 syn::Data::Struct(syn::DataStruct {
19 fields: syn::Fields::Unnamed(fields),
20 ..
21 }) => {
22 &fields.unnamed
23 },
24 _ => panic!("Expected a struct"),
25 };
26 let fields: Vec<syn::Ident> = fields.iter().enumerate().map(|(i, f)| f.ident.clone().unwrap_or_else(|| syn::Ident::new(&i.to_string(), Span::call_site()))).collect();
27 let generics = &ast.generics;
28 let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
29
30 let fields_code: Vec<_> = fields.into_iter().map(|f| {
31 quote!{
32 self.#f.update(h);
33 }
34 }).collect();
35 let ret = quote! {
36 impl #impl_generics simple_hash::Hashable for #name #ty_generics #where_clause {
37 fn update<H: simple_hash::Hasher>(&self, h: &mut H) {
38 #(#fields_code)*
39 }
40 }
41 };
42
43 ret.into()
44}