enum_methods/
is_a.rs

1use syn::*;
2use quote;
3use util::*;
4
5/// Gives implementations of is_a_* functions for tuples.
6pub(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}