1use syn::*;
2use quote;
3use util::*;
4
5pub(crate) fn impl_enum_is_a(ast: &DeriveInput) -> quote::Tokens {
7 let ref name = ast.ident;
8
9 let variants =
10 if let Body::Enum(ref e) = ast.body { e }
11 else { unreachable!() };
12
13 macro_rules! is_a_filter {
14 () => {
15 variants.iter()
16 .filter(|v| if let VariantData::Tuple(_) = v.data { true } else { false })
17 };
18 }
19
20 let variant_names = is_a_filter!()
21 .map(|v| v.ident.clone())
22 .collect::<Vec<Ident>>();
23
24 let function_names = is_a_filter!()
25 .map(|v| format!("is_{}", to_snake_case(&v.ident)).into())
26 .collect::<Vec<Ident>>();
27
28 let variant_counts = is_a_filter!()
29 .map(|v| vec!(Ident::new("_"); v.data.fields().len()))
30 .collect::<Vec<_>>();
31
32 let getter_names = vec!(name.clone(); variant_names.len());
33
34 quote! {
35 #[allow(dead_code)]
36 impl #name {
37 #(pub fn #function_names(&self) -> bool {
38 if let &#getter_names::#variant_names(#(#variant_counts),*) = self {
39 true
40 }
41 else {
42 false
43 }
44 })*
45 }
46 }
47}
48
49pub(crate) fn impl_unit_enum_is_a(ast: &DeriveInput) -> quote::Tokens {
50 let ref name = ast.ident;
51
52 let variants =
53 if let Body::Enum(ref e) = ast.body { e }
54 else { unreachable!() };
55
56 macro_rules! is_a_filter {
57 () => {
58 variants.iter()
59 .filter(|v| if let VariantData::Unit = v.data { true } else { false })
60 };
61 }
62
63 let variant_names = is_a_filter!()
64 .map(|v| v.ident.clone())
65 .collect::<Vec<Ident>>();
66
67 let function_names = is_a_filter!()
68 .map(|v| format!("is_{}", to_snake_case(&v.ident)).into())
69 .collect::<Vec<Ident>>();
70
71 let getter_names = vec!(name.clone(); variant_names.len());
72
73 quote! {
74 #[allow(dead_code)]
75 impl #name {
76 #(pub fn #function_names(&self) -> bool {
77 if let &#getter_names::#variant_names = self {
78 true
79 }
80 else {
81 false
82 }
83 })*
84 }
85 }
86}
87
88pub(crate) fn impl_struct_enum_is_a(ast: &DeriveInput) -> quote::Tokens {
89 let ref name = ast.ident;
90
91 let variants =
92 if let Body::Enum(ref e) = ast.body { e }
93 else { unreachable!() };
94
95 macro_rules! is_a_filter {
96 () => {
97 variants.iter()
98 .filter(|v| if let VariantData::Struct(_) = v.data { true } else { false })
99 };
100 }
101
102 let variant_names = is_a_filter!()
103 .map(|v| v.ident.clone())
104 .collect::<Vec<Ident>>();
105
106 let function_names = is_a_filter!()
107 .map(|v| format!("is_{}", to_snake_case(&v.ident)).into())
108 .collect::<Vec<Ident>>();
109
110 let variant_field_names = is_a_filter!()
111 .map(|v| v.data.fields().iter().map(|ref f| f.ident.as_ref().unwrap()).collect::<Vec<_>>())
112 .collect::<Vec<_>>();
113
114 let variant_counts = is_a_filter!()
115 .map(|v| vec!(Ident::new("_"); v.data.fields().len()))
116 .collect::<Vec<_>>();
117
118 let getter_names = vec!(name.clone(); variant_names.len());
119
120 quote! {
121 #[allow(dead_code)]
122 impl #name {
123 #(pub fn #function_names(&self) -> bool {
124 if let &#getter_names::#variant_names { #(#variant_field_names: #variant_counts),* } = self {
125 true
126 }
127 else {
128 false
129 }
130 })*
131 }
132 }
133}