1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
extern crate proc_macro; extern crate syn; #[macro_use] extern crate quote; extern crate merkle_light; use proc_macro::TokenStream; #[proc_macro_derive(Hashable)] pub fn derive_hashable(input: TokenStream) -> TokenStream { let s = input.to_string(); let ast = syn::parse_derive_input(&s).unwrap(); let gen = impl_hashable(&ast); gen.parse().unwrap() } fn impl_hashable(ast: &syn::DeriveInput) -> quote::Tokens { let body = match ast.body { syn::Body::Struct(ref s) => s, _ => panic!("#[derive(Hashable)] is only defined for structs."), }; let stmts: Vec<_> = match *body { syn::VariantData::Struct(ref fields) => { fields.iter().enumerate().map(hash_field_map).collect() } syn::VariantData::Tuple(ref fields) => { fields.iter().enumerate().map(hash_field_map).collect() } syn::VariantData::Unit => panic!("#[derive(Hashable)] is not defined for Unit structs."), }; let name = &ast.ident; let dummy_const = syn::Ident::new(format!("_IMPL_HASHABLE_FOR_{}", name).to_uppercase()); quote! { const #dummy_const: () = { extern crate merkle_light; use std::hash::Hasher; use merkle_light::hash::Hashable; impl<H: Hasher> Hashable<H> for #name { fn hash(&self, state: &mut H) { #(#stmts)* } } }; } } fn hash_field_map(tuple: (usize, &syn::Field)) -> quote::Tokens { hash_field(tuple.0, tuple.1) } fn hash_field(index: usize, f: &syn::Field) -> quote::Tokens { let mut ty = f.ty.clone(); loop { match ty { syn::Ty::Path(_, ref path) => { path.segments.first().expect( "there must be at least 1 segment", ); break; } syn::Ty::Rptr(_, bty) => { ty = bty.ty.clone(); } _ => panic!(format!("hashing not supported: {:?}", ty)), }; } match f.ident { Some(ref ident) => quote! { self.#ident.hash(state); }, None => quote! { self.#index.hash(state); }, } }