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
79
80
81
82
83
84
85
86
87
88
89
#![recursion_limit="128"]
#[macro_use] extern crate quote;
extern crate proc_macro;
extern crate proc_macro2; use proc_macro2::{Ident,Span};
extern crate syn; use syn::Type;
#[proc_macro_derive(SmartHash)]
pub fn smart_hash(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = syn::parse(input).unwrap();
impl_smart_hash(&ast)
}
fn impl_smart_hash(ast : &syn::DeriveInput) -> proc_macro::TokenStream {
let name = &ast.ident;
let name_opt = Ident::new(&format!("{}Opt",name),Span::call_site());
let mut m_prime : Vec<Ident> = Vec::new();
let mut t_prime : Vec<Type> = Vec::new();
if let syn::Data::Struct(ref datastruct) = ast.data {
if let syn::Fields::Named(ref fields) = datastruct.fields {
for p in &fields.named {
if let Some(ref ident) = p.ident {
m_prime.push(ident.clone());
}
t_prime.push(p.ty.clone());
}
}
}
let ref m = m_prime;
let m2 = m;
let m3 = m;
let m4 = m;
let ref t = t_prime;
let gen = quote! {
#[derive(Hash, Debug)]
pub struct #name_opt {
#(pub #m : Option<#t>),*
}
impl Eq for #name_opt { }
impl smart_hash::traits::SmartHashOpt for #name_opt { }
impl PartialEq for #name_opt {
fn eq(&self, other : &#name_opt) -> bool {
#( ((self.#m == other.#m2) || other.#m3.is_none() || self.#m4.is_none()) ) && *
}
}
impl Default for #name_opt {
fn default() -> #name_opt {
#name_opt {
#( #m : None ),*
}
}
}
impl smart_hash::traits::SmartHash for #name {
type option = #name_opt;
fn into_option(&self) -> #name_opt {
#name_opt {
#(#m : Some(self.#m2.clone())),*
}
}
}
};
gen.into()
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}