enum_methods/lib.rs
1/*!
2# enum-methods
3
4[](https://travis-ci.org/alekratz/enum-methods)
5[](https://crates.io/crates/enum-methods)
6
7Enum getter/`is_*` method generation.
8
9#### Please note that this crate is unstable and is subject to change frequently.
10I will attempt to prevent *seriously* breaking changes after we hit 0.1.0.
11
12# Links
13
14* [Github](https://github.com/alekratz/enum-methods)
15* [crates.io](https://crates.io/crates/enum-methods)
16* [docs.rs](https://docs.rs/enum-methods/0.0.8/enum_methods/)
17
18# Usage
19
20In your `Cargo.toml`, add this line under your `[dependencies]` section:
21
22```toml,no_run
23enum-methods = "0.0.8"
24```
25
26To use, simply derive and call methods (see the example below).
27
28# Why?
29
30Usually when you write an enum with one or zero values, you might want to
31add a set of getters for them. As such:
32
33```rust
34#[derive(Debug)]
35enum MyEnum {
36 FooBarBaz(i64),
37 BazBarFoo(String),
38 // ... and others
39}
40
41impl MyEnum {
42 pub fn foo_bar_baz(&self) -> i64 {
43 if let &MyEnum::FooBarBaz(i) = self {
44 i
45 }
46 else {
47 panic!("called MyEnum::FooBarBaz() on {:?}", self)
48 }
49 }
50 // et cetera
51}
52
53```
54
55But this gets tedious, and adds a lot code for this simple functionality.
56Enter `enum-methods`.
57
58Instead of doing the above with the `if let ... else { panic!(...) }`, you
59simply derive from the `EnumIntoGetters`
60
61```rust
62#[macro_use]
63extern crate enum_methods;
64
65#[derive(EnumIntoGetters, EnumAsGetters, EnumIsA, Debug)]
66enum MyEnum {
67 FooBarBaz(i64),
68 BazBarFoo(String),
69 // ... and others
70}
71
72fn main() {
73 let my_foo = MyEnum::FooBarBaz(42);
74 // EnumIsA - creates is_* methods for every member
75 if my_foo.is_foo_bar_baz() {
76 // EnumAsGetters - gets a reference to the enum, panicking if it is
77 // not the specified variant
78 assert_eq!(*my_foo.as_foo_bar_baz(), 42);
79 // EnumIntoGetters - consumes the enum, yielding its owned value,
80 // and panicking if it is not the specified variant
81 assert_eq!(my_foo.into_foo_bar_baz(), 42);
82 }
83}
84```
85
86# Requirements and gotchas
87
88Right now, `enum-methods` has four derivable options:
89
90* `EnumAsGetters` for generating `as_*` methods, which return a reference.
91* `EnumIntoGetters` for generating `into_*` methods, which consume the enum
92 and returns the data held by the variant.
93* `EnumToGetters` for generating `to_*` methods, which returns a clone of
94 the data held by the variant.
95* `EnumIsA` for generating `is_*` methods, which return a boolean indicating
96 whether the enum matches that variant.
97
98`EnumAsGetters`, `EnumIntoGetters`, and `EnumToGetters` have some limitations.
99
100* Any enum variant which has exactly 1 member will have a getter generated for
101 it. All other variants are ignored.
102* Enums which derive from `EnumIntoGetters` must also derive from `Debug` - this
103 is for when a method is called for the wrong variant and needs to `panic!`.
104
105Furthermore, `EnumToGetters` is *only* for enums whose variants implement
106`Clone`. There is not yet support for th
107
108`EnumIsA` is much simpler than the previous; it simply adds `is_*`
109methods returning a boolean for whether the variant matches or not.
110
111**For all generated methods, all names are automatically converted to
112snake_case**.
113
114# License
115
116This software is released under the Apache license 2.0. See the LICENSE file
117for more details.
118
119*/
120
121extern crate proc_macro;
122#[macro_use]
123extern crate quote;
124extern crate syn;
125
126mod getters;
127mod is_a;
128mod util;
129
130use getters::*;
131use is_a::*;
132use proc_macro::TokenStream;
133use syn::*;
134
135// TODO : map types for what a reference should return in its getter
136// e.g. String -> &str in the getter
137
138#[proc_macro_derive(EnumAsGetters)]
139#[doc(hidden)]
140pub fn enum_as_getters(input: TokenStream) -> TokenStream {
141 let s = input.to_string();
142 let ast = parse_derive_input(&s).unwrap();
143 let getters = impl_enum_as_getters(&ast);
144 //panic!("{:#?}", getters);
145 getters.parse().unwrap()
146}
147
148#[proc_macro_derive(EnumIntoGetters)]
149#[doc(hidden)]
150pub fn enum_into_getters(input: TokenStream) -> TokenStream {
151 let s = input.to_string();
152 let ast = parse_derive_input(&s).unwrap();
153 let getters = impl_enum_into_getters(&ast);
154 getters.parse().unwrap()
155}
156
157#[proc_macro_derive(EnumToGetters)]
158#[doc(hidden)]
159pub fn enum_to_getters(input: TokenStream) -> TokenStream {
160 let s = input.to_string();
161 let ast = parse_derive_input(&s).unwrap();
162 let getters = impl_enum_to_getters(&ast);
163 getters.parse().unwrap()
164}
165
166#[proc_macro_derive(EnumIsA)]
167#[doc(hidden)]
168pub fn enum_is_a(input: TokenStream) -> TokenStream {
169 let s = input.to_string();
170 let ast = parse_derive_input(&s).unwrap();
171 let mut gen = impl_enum_is_a(&ast);
172 gen.append(&mut impl_struct_enum_is_a(&ast));
173 gen.append(&mut impl_unit_enum_is_a(&ast));
174 gen.parse().unwrap()
175}
176