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