]>
Commit | Line | Data |
---|---|---|
a1dfa0c6 XL |
1 | // Copyright (c) 2015 Anders Kaseorg <andersk@mit.edu> |
2 | ||
3 | // Permission is hereby granted, free of charge, to any person obtaining | |
4 | // a copy of this software and associated documentation files (the | |
5 | // “Software”), to deal in the Software without restriction, including | |
6 | // without limitation the rights to use, copy, modify, merge, publish, | |
7 | // distribute, sublicense, and/or sell copies of the Software, and to | |
8 | // permit persons to whom the Software is furnished to do so, subject to | |
9 | // the following conditions: | |
10 | ||
11 | // The above copyright notice and this permission notice shall be | |
12 | // included in all copies or substantial portions of the Software. | |
13 | ||
14 | // THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, | |
15 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | |
17 | // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY | |
18 | // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | |
19 | // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE | |
20 | // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
21 | ||
a1dfa0c6 XL |
22 | //! This crate exports a macro `enum_from_primitive!` that wraps an |
23 | //! `enum` declaration and automatically adds an implementation of | |
24 | //! `num::FromPrimitive` (reexported here), to allow conversion from | |
9fa01778 | 25 | //! primitive integers to the enum. It therefore provides an |
a1dfa0c6 XL |
26 | //! alternative to the built-in `#[derive(FromPrimitive)]`, which |
27 | //! requires the unstable `std::num::FromPrimitive` and is disabled in | |
28 | //! Rust 1.0. | |
29 | //! | |
30 | //! # Example | |
31 | //! | |
32 | //! ``` | |
33 | //! #[macro_use] extern crate enum_primitive; | |
34 | //! extern crate num_traits; | |
35 | //! use num_traits::FromPrimitive; | |
36 | //! | |
37 | //! enum_from_primitive! { | |
38 | //! #[derive(Debug, PartialEq)] | |
39 | //! enum FooBar { | |
40 | //! Foo = 17, | |
41 | //! Bar = 42, | |
42 | //! Baz, | |
43 | //! } | |
44 | //! } | |
45 | //! | |
46 | //! fn main() { | |
47 | //! assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo)); | |
48 | //! assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar)); | |
49 | //! assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz)); | |
50 | //! assert_eq!(FooBar::from_i32(91), None); | |
51 | //! } | |
52 | //! ``` | |
53 | ||
a1dfa0c6 XL |
54 | pub mod num_traits { |
55 | pub trait FromPrimitive: Sized { | |
56 | fn from_i64(n: i64) -> Option<Self>; | |
57 | fn from_u64(n: u64) -> Option<Self>; | |
58 | } | |
59 | } | |
60 | ||
61 | pub use std::option::Option; | |
62 | pub use num_traits::FromPrimitive; | |
63 | ||
64 | /// Helper macro for internal use by `enum_from_primitive!`. | |
65 | #[macro_export] | |
66 | macro_rules! enum_from_primitive_impl_ty { | |
67 | ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => { | |
68 | #[allow(non_upper_case_globals, unused)] | |
69 | fn $meth(n: $ty) -> $crate::Option<Self> { | |
70 | $( if n == $name::$variant as $ty { | |
71 | $crate::Option::Some($name::$variant) | |
72 | } else )* { | |
73 | $crate::Option::None | |
74 | } | |
75 | } | |
76 | }; | |
77 | } | |
78 | ||
79 | /// Helper macro for internal use by `enum_from_primitive!`. | |
80 | #[macro_export] | |
81 | #[macro_use(enum_from_primitive_impl_ty)] | |
82 | macro_rules! enum_from_primitive_impl { | |
83 | ($name:ident, $( $variant:ident )*) => { | |
84 | impl $crate::FromPrimitive for $name { | |
85 | enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* } | |
86 | enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* } | |
87 | } | |
88 | }; | |
89 | } | |
90 | ||
91 | /// Wrap this macro around an `enum` declaration to get an | |
92 | /// automatically generated implementation of `num::FromPrimitive`. | |
93 | #[macro_export] | |
94 | #[macro_use(enum_from_primitive_impl)] | |
95 | macro_rules! enum_from_primitive { | |
96 | ( | |
97 | $( #[$enum_attr:meta] )* | |
98 | enum $name:ident { | |
99 | $( $( #[$variant_attr:meta] )* $variant:ident ),+ | |
100 | $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* | |
101 | } | |
102 | ) => { | |
103 | $( #[$enum_attr] )* | |
104 | enum $name { | |
105 | $( $( #[$variant_attr] )* $variant ),+ | |
106 | $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* | |
107 | } | |
108 | enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } | |
109 | }; | |
110 | ||
111 | ( | |
112 | $( #[$enum_attr:meta] )* | |
113 | enum $name:ident { | |
114 | $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* | |
115 | } | |
116 | ) => { | |
117 | $( #[$enum_attr] )* | |
118 | enum $name { | |
119 | $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* | |
120 | } | |
121 | enum_from_primitive_impl! { $name, $( $( $variant )+ )* } | |
122 | }; | |
123 | ||
124 | ( | |
125 | $( #[$enum_attr:meta] )* | |
126 | enum $name:ident { | |
127 | $( $( #[$variant_attr:meta] )* $variant:ident ),+ | |
128 | $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, | |
129 | } | |
130 | ) => { | |
131 | $( #[$enum_attr] )* | |
132 | enum $name { | |
133 | $( $( #[$variant_attr] )* $variant ),+ | |
134 | $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, | |
135 | } | |
136 | enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } | |
137 | }; | |
138 | ||
139 | ( | |
140 | $( #[$enum_attr:meta] )* | |
141 | enum $name:ident { | |
142 | $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, | |
143 | } | |
144 | ) => { | |
145 | $( #[$enum_attr] )* | |
146 | enum $name { | |
147 | $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, | |
148 | } | |
149 | enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } | |
150 | }; | |
151 | ||
152 | ( | |
153 | $( #[$enum_attr:meta] )* | |
154 | pub enum $name:ident { | |
155 | $( $( #[$variant_attr:meta] )* $variant:ident ),+ | |
156 | $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )* | |
157 | } | |
158 | ) => { | |
159 | $( #[$enum_attr] )* | |
160 | pub enum $name { | |
161 | $( $( #[$variant_attr] )* $variant ),+ | |
162 | $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )* | |
163 | } | |
164 | enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } | |
165 | }; | |
166 | ||
167 | ( | |
168 | $( #[$enum_attr:meta] )* | |
169 | pub enum $name:ident { | |
170 | $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),* | |
171 | } | |
172 | ) => { | |
173 | $( #[$enum_attr] )* | |
174 | pub enum $name { | |
175 | $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),* | |
176 | } | |
177 | enum_from_primitive_impl! { $name, $( $( $variant )+ )* } | |
178 | }; | |
179 | ||
180 | ( | |
181 | $( #[$enum_attr:meta] )* | |
182 | pub enum $name:ident { | |
183 | $( $( #[$variant_attr:meta] )* $variant:ident ),+ | |
184 | $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*, | |
185 | } | |
186 | ) => { | |
187 | $( #[$enum_attr] )* | |
188 | pub enum $name { | |
189 | $( $( #[$variant_attr] )* $variant ),+ | |
190 | $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*, | |
191 | } | |
192 | enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* } | |
193 | }; | |
194 | ||
195 | ( | |
196 | $( #[$enum_attr:meta] )* | |
197 | pub enum $name:ident { | |
198 | $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+, | |
199 | } | |
200 | ) => { | |
201 | $( #[$enum_attr] )* | |
202 | pub enum $name { | |
203 | $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+, | |
204 | } | |
205 | enum_from_primitive_impl! { $name, $( $( $variant )+ )+ } | |
206 | }; | |
207 | } |