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!("hashing not supported: {:?}", ty),
};
}
match f.ident {
Some(ref ident) => quote! { self.#ident.hash(state); },
None => quote! { self.#index.hash(state); },
}
}