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