enum_primitive/
lib.rs

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
22
23//! This crate exports a macro `enum_from_primitive!` that wraps an
24//! `enum` declaration and automatically adds an implementation of
25//! `num::FromPrimitive` (reexported here), to allow conversion from
26//! primitive integers to the enum.  It therefore provides an
27//! alternative to the built-in `#[derive(FromPrimitive)]`, which
28//! requires the unstable `std::num::FromPrimitive` and is disabled in
29//! Rust 1.0.
30//!
31//! # Example
32//!
33//! ```
34//! #[macro_use] extern crate enum_primitive;
35//! extern crate num_traits;
36//! use num_traits::FromPrimitive;
37//!
38//! enum_from_primitive! {
39//! #[derive(Debug, PartialEq)]
40//! enum FooBar {
41//!     Foo = 17,
42//!     Bar = 42,
43//!     Baz,
44//! }
45//! }
46//!
47//! fn main() {
48//!     assert_eq!(FooBar::from_i32(17), Some(FooBar::Foo));
49//!     assert_eq!(FooBar::from_i32(42), Some(FooBar::Bar));
50//!     assert_eq!(FooBar::from_i32(43), Some(FooBar::Baz));
51//!     assert_eq!(FooBar::from_i32(91), None);
52//! }
53//! ```
54
55
56extern crate num_traits;
57
58pub use std::option::Option;
59pub use num_traits::FromPrimitive;
60
61/// Helper macro for internal use by `enum_from_primitive!`.
62#[macro_export]
63macro_rules! enum_from_primitive_impl_ty {
64    ($meth:ident, $ty:ty, $name:ident, $( $variant:ident )*) => {
65        #[allow(non_upper_case_globals, unused)]
66        fn $meth(n: $ty) -> $crate::Option<Self> {
67            $( if n == $name::$variant as $ty {
68                $crate::Option::Some($name::$variant)
69            } else )* {
70                $crate::Option::None
71            }
72        }
73    };
74}
75
76/// Helper macro for internal use by `enum_from_primitive!`.
77#[macro_export]
78#[macro_use(enum_from_primitive_impl_ty)]
79macro_rules! enum_from_primitive_impl {
80    ($name:ident, $( $variant:ident )*) => {
81        impl $crate::FromPrimitive for $name {
82            enum_from_primitive_impl_ty! { from_i64, i64, $name, $( $variant )* }
83            enum_from_primitive_impl_ty! { from_u64, u64, $name, $( $variant )* }
84        }
85    };
86}
87
88/// Wrap this macro around an `enum` declaration to get an
89/// automatically generated implementation of `num::FromPrimitive`.
90#[macro_export]
91#[macro_use(enum_from_primitive_impl)]
92macro_rules! enum_from_primitive {
93    (
94        $( #[$enum_attr:meta] )*
95        enum $name:ident {
96            $( $( #[$variant_attr:meta] )* $variant:ident ),+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
97        }
98    ) => {
99        $( #[$enum_attr] )*
100        enum $name {
101            $( $( #[$variant_attr] )* $variant ),+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
102        }
103        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
104    };
105
106    (
107        $( #[$enum_attr:meta] )*
108        enum $name:ident {
109            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
110        }
111    ) => {
112        $( #[$enum_attr] )*
113        enum $name {
114            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
115        }
116        enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
117    };
118
119    (
120        $( #[$enum_attr:meta] )*
121        enum $name:ident {
122            $( $( #[$variant_attr:meta] )* $variant:ident ),+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
123        }
124    ) => {
125        $( #[$enum_attr] )*
126        enum $name {
127            $( $( #[$variant_attr] )* $variant ),+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
128        }
129        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
130    };
131
132    (
133        $( #[$enum_attr:meta] )*
134        enum $name:ident {
135            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
136        }
137    ) => {
138        $( #[$enum_attr] )*
139        enum $name {
140            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
141        }
142        enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
143    };
144
145    (
146        $( #[$enum_attr:meta] )*
147        pub enum $name:ident {
148            $( $( #[$variant_attr:meta] )* $variant:ident ),+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*
149        }
150    ) => {
151        $( #[$enum_attr] )*
152        pub enum $name {
153            $( $( #[$variant_attr] )* $variant ),+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*
154        }
155        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
156    };
157
158    (
159        $( #[$enum_attr:meta] )*
160        pub enum $name:ident {
161            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),*
162        }
163    ) => {
164        $( #[$enum_attr] )*
165        pub enum $name {
166            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),*
167        }
168        enum_from_primitive_impl! { $name, $( $( $variant )+ )* }
169    };
170
171    (
172        $( #[$enum_attr:meta] )*
173        pub enum $name:ident {
174            $( $( #[$variant_attr:meta] )* $variant:ident ),+ $( = $discriminator:expr, $( $( #[$variant_two_attr:meta] )* $variant_two:ident ),+ )*,
175        }
176    ) => {
177        $( #[$enum_attr] )*
178        pub enum $name {
179            $( $( #[$variant_attr] )* $variant ),+ $( = $discriminator, $( $( #[$variant_two_attr] )* $variant_two ),+ )*,
180        }
181        enum_from_primitive_impl! { $name, $( $variant )+ $( $( $variant_two )+ )* }
182    };
183
184    (
185        $( #[$enum_attr:meta] )*
186        pub enum $name:ident {
187            $( $( $( #[$variant_attr:meta] )* $variant:ident ),+ = $discriminator:expr ),+,
188        }
189    ) => {
190        $( #[$enum_attr] )*
191        pub enum $name {
192            $( $( $( #[$variant_attr] )* $variant ),+ = $discriminator ),+,
193        }
194        enum_from_primitive_impl! { $name, $( $( $variant )+ )+ }
195    };
196}