enum_unitary/
lib.rs

1//! `EnumUnitary` trait and `enum_unitary!` macro.
2//!
3//! [Repository](https://github.com/spearman/enum-unitary)
4
5extern crate num_traits;
6
7pub use enum_iterator;
8pub use num_traits::{FromPrimitive, ToPrimitive};
9
10//
11//  trait EnumUnitary
12//
13/// A collection of constraints for unitary enums.
14///
15/// See the `enum_unitary!` macro for defining instances of this trait.
16// TODO: expose more constraints ?
17pub trait EnumUnitary : Clone
18  // NB: as of Rust 1.22, the *last* of the following `Into` constraints
19  // seems to be chosen by default and using `.into` for one of the other
20  // types requires using disambiguation syntax; we choose `usize` here since
21  // it is commonly used as an index type.
22  + Into <i64> + Into <u64> + Into <isize> + Into <usize>
23  + ToPrimitive + FromPrimitive + enum_iterator::Sequence
24{ }
25
26//
27//  enum_unitary!
28//
29/// Derive and implement extra traits for "unitary" enums (i.e. enums where
30/// variants do not have payloads):
31///
32/// - implements `num_traits` traits `Bounded`, `ToPrimitive`, `FromPrimitive`
33/// - implements primitive conversion types
34///
35/// Note that `Clone` is also automatically derived so there will be an error if
36/// it is given in a derive attribute.
37///
38/// Currently explicit discriminators are not allowed: enum variants will be
39/// numbered consecutively starting from `0`.
40///
41/// # Examples
42///
43/// ```
44/// use enum_unitary::{enum_unitary, EnumUnitary, FromPrimitive,
45///   ToPrimitive};
46///
47/// fn main () {
48///   enum_unitary! {
49///     #[derive(Debug, PartialEq)]
50///     pub enum E {
51///       A, B, C
52///     }
53///   }
54///   assert_eq!(enum_iterator::cardinality::<E>(), 3);
55///   assert_eq!(Into::<usize>::into (E::A), 0);
56///   assert_eq!(Into::<usize>::into (E::B), 1);
57///   assert_eq!(Into::<usize>::into (E::C), 2);
58///   assert_eq!(enum_iterator::first::<E>().unwrap(), E::A);
59///   assert_eq!(enum_iterator::last::<E>().unwrap(),  E::C);
60///   let mut i = enum_iterator::all::<E>();
61///   assert_eq!(i.next(), Some (E::A));
62///   assert_eq!(i.next(), Some (E::B));
63///   assert_eq!(i.next(), Some (E::C));
64///   assert_eq!(i.next(), None);
65///   assert_eq!(enum_iterator::next (&E::A), Some (E::B));
66///   assert_eq!(enum_iterator::previous (&E::A), None);
67///   assert_eq!(enum_iterator::next (&E::B), Some (E::C));
68///   assert_eq!(enum_iterator::previous (&E::B), Some (E::A));
69///   assert_eq!(enum_iterator::next (&E::C), None);
70///   assert_eq!(enum_iterator::previous (&E::C), Some (E::B));
71/// }
72/// ```
73
74#[macro_export]
75macro_rules! enum_unitary {
76  //
77  //  private
78  //
79  (
80    $(#[$attrs:meta])*
81    enum $enum:ident { $($variant:ident),* }
82  ) => {
83    $(#[$attrs])*
84    #[derive(Clone, $crate::enum_iterator::Sequence)]
85    enum $enum {
86      $($variant),*
87    }
88
89    impl From <$enum> for isize {
90      fn from (x : $enum) -> Self {
91        x as isize
92      }
93    }
94    impl From <$enum> for usize {
95      fn from (x : $enum) -> Self {
96        x as usize
97      }
98    }
99    impl From <$enum> for i64 {
100      fn from (x : $enum) -> Self {
101        x as i64
102      }
103    }
104    impl From <$enum> for u64 {
105      fn from (x : $enum) -> Self {
106        x as u64
107      }
108    }
109
110    impl $crate::FromPrimitive for $enum {
111      fn from_i64 (x : i64) -> Option <Self> {
112        const VARIANTS : [$enum; $crate::enum_iterator::cardinality::<$enum>()]
113          = [$($enum::$variant),*];
114        VARIANTS.get (x as usize).cloned()
115      }
116      fn from_u64 (x : u64) -> Option <Self> {
117        const VARIANTS : [$enum; $crate::enum_iterator::cardinality::<$enum>()]
118          = [$($enum::$variant),*];
119        VARIANTS.get (x as usize).cloned()
120      }
121    }
122
123    impl $crate::ToPrimitive for $enum {
124      fn to_i64 (&self) -> Option <i64> {
125        Some (self.clone() as i64)
126      }
127      fn to_u64 (&self) -> Option <u64> {
128        Some (self.clone() as u64)
129      }
130    }
131
132    impl $crate::EnumUnitary for $enum { }
133  };
134
135  //
136  //  public
137  //
138  (
139    $(#[$attrs:meta])*
140    pub enum $enum:ident { $($variant:ident),* }
141  ) => {
142    $(#[$attrs])*
143    #[derive(Clone, $crate::enum_iterator::Sequence)]
144    pub enum $enum {
145      $($variant),*
146    }
147
148    impl From <$enum> for isize {
149      fn from (x : $enum) -> Self {
150        x as isize
151      }
152    }
153    impl From <$enum> for usize {
154      fn from (x: $enum) -> Self {
155        x as usize
156      }
157    }
158    impl From <$enum> for i64 {
159      fn from (x : $enum) -> Self {
160        x as i64
161      }
162    }
163    impl From <$enum> for u64 {
164      fn from (x: $enum) -> Self {
165        x as u64
166      }
167    }
168
169    impl $crate::FromPrimitive for $enum {
170      fn from_i64 (x : i64) -> Option <Self> {
171        const VARIANTS : [$enum; $crate::enum_iterator::cardinality::<$enum>()]
172          = [$($enum::$variant),*];
173        VARIANTS.get (x as usize).cloned()
174      }
175      fn from_u64 (x: u64) -> Option <Self> {
176        const VARIANTS : [$enum; $crate::enum_iterator::cardinality::<$enum>()]
177          = [$($enum::$variant),*];
178        VARIANTS.get (x as usize).cloned()
179      }
180    }
181
182    impl $crate::ToPrimitive for $enum {
183      fn to_i64 (&self) -> Option <i64> {
184        Some (self.clone() as i64)
185      }
186      fn to_u64 (&self) -> Option <u64> {
187        Some (self.clone() as u64)
188      }
189    }
190
191    impl $crate::EnumUnitary for $enum { }
192  };
193}
194
195//
196//  example enum
197//
198#[cfg(doc)]
199enum_unitary!{
200  /// This is an example enum generated by `enum_unitary!`
201  pub enum Example {
202    A, B, C
203  }
204}
205
206//
207//  mod tests
208//
209#[cfg(test)]
210mod tests {
211  #[test]
212  fn test_unit() {
213    use crate::{FromPrimitive, ToPrimitive};
214
215    // private enum
216    enum_unitary!{
217      #[derive(Debug, PartialEq)]
218      enum Myenum1 {
219        A, B, C
220      }
221    }
222    assert_eq!(enum_iterator::cardinality::<Myenum1>(), 3);
223    assert_eq!(Into::<usize>::into (Myenum1::A), 0);
224    assert_eq!(Into::<usize>::into (Myenum1::B), 1);
225    assert_eq!(Into::<usize>::into (Myenum1::C), 2);
226    assert_eq!(Some (Myenum1::A), Myenum1::from_usize (0));
227    assert_eq!(Some (Myenum1::B), Myenum1::from_usize (1));
228    assert_eq!(Some (Myenum1::C), Myenum1::from_usize (2));
229    assert_eq!(None, Myenum1::from_usize (3));
230    assert_eq!(Some (0), Myenum1::A.to_usize());
231    assert_eq!(Some (1), Myenum1::B.to_usize());
232    assert_eq!(Some (2), Myenum1::C.to_usize());
233    assert_eq!(enum_iterator::first::<Myenum1>().unwrap(), Myenum1::A);
234    assert_eq!(enum_iterator::last::<Myenum1>().unwrap(), Myenum1::C);
235    let mut i = enum_iterator::all::<Myenum1>();
236    assert_eq!(i.next(), Some (Myenum1::A));
237    assert_eq!(i.next(), Some (Myenum1::B));
238    assert_eq!(i.next(), Some (Myenum1::C));
239    assert_eq!(i.next(), None);
240    assert_eq!(enum_iterator::next (&Myenum1::A), Some (Myenum1::B));
241    assert_eq!(enum_iterator::previous (&Myenum1::A), None);
242    assert_eq!(enum_iterator::next (&Myenum1::B), Some (Myenum1::C));
243    assert_eq!(enum_iterator::previous (&Myenum1::B), Some (Myenum1::A));
244    assert_eq!(enum_iterator::next (&Myenum1::C), None);
245    assert_eq!(enum_iterator::previous (&Myenum1::C), Some (Myenum1::B));
246
247    // public enum
248    enum_unitary!{
249      #[derive(Debug, PartialEq)]
250      pub enum Myenum2 {
251        A, B, C
252      }
253    }
254    assert_eq!(enum_iterator::cardinality::<Myenum2>(), 3);
255    assert_eq!(Into::<usize>::into (Myenum2::A), 0);
256    assert_eq!(Into::<usize>::into (Myenum2::B), 1);
257    assert_eq!(Into::<usize>::into (Myenum2::C), 2);
258    assert_eq!(Some (Myenum2::A), Myenum2::from_usize (0));
259    assert_eq!(Some (Myenum2::B), Myenum2::from_usize (1));
260    assert_eq!(Some (Myenum2::C), Myenum2::from_usize (2));
261    assert_eq!(None, Myenum2::from_usize (3));
262    assert_eq!(Some (0), Myenum2::A.to_usize());
263    assert_eq!(Some (1), Myenum2::B.to_usize());
264    assert_eq!(Some (2), Myenum2::C.to_usize());
265    assert_eq!(enum_iterator::first::<Myenum2>().unwrap(), Myenum2::A);
266    assert_eq!(enum_iterator::last::<Myenum2>().unwrap(), Myenum2::C);
267    let mut i = enum_iterator::all::<Myenum2>();
268    assert_eq!(i.next(), Some (Myenum2::A));
269    assert_eq!(i.next(), Some (Myenum2::B));
270    assert_eq!(i.next(), Some (Myenum2::C));
271    assert_eq!(i.next(), None);
272    assert_eq!(enum_iterator::next (&Myenum2::A), Some (Myenum2::B));
273    assert_eq!(enum_iterator::previous (&Myenum2::A), None);
274    assert_eq!(enum_iterator::next (&Myenum2::B), Some (Myenum2::C));
275    assert_eq!(enum_iterator::previous (&Myenum2::B), Some (Myenum2::A));
276    assert_eq!(enum_iterator::next (&Myenum2::C), None);
277    assert_eq!(enum_iterator::previous (&Myenum2::C), Some (Myenum2::B));
278
279    // private singleton enum
280    enum_unitary!{
281      #[derive(Debug, PartialEq)]
282      enum Myenum3 {
283        X
284      }
285    }
286    assert_eq!(enum_iterator::cardinality::<Myenum3>(), 1);
287    assert_eq!(Into::<usize>::into (Myenum3::X), 0);
288    assert_eq!(Some (Myenum3::X), Myenum3::from_usize (0));
289    assert_eq!(None, Myenum3::from_usize (1));
290    assert_eq!(Some (0), Myenum3::X.to_usize());
291    assert_eq!(enum_iterator::first::<Myenum3>().unwrap(), Myenum3::X);
292    assert_eq!(enum_iterator::last::<Myenum3>().unwrap(), Myenum3::X);
293    let mut i = enum_iterator::all::<Myenum3>();
294    assert_eq!(i.next(), Some (Myenum3::X));
295    assert_eq!(i.next(), None);
296    assert_eq!(enum_iterator::next (&Myenum3::X), None);
297    assert_eq!(enum_iterator::previous (&Myenum3::X), None);
298
299    // public singleton enum
300    enum_unitary!{
301      #[derive(Debug, PartialEq)]
302      pub enum Myenum4 {
303        X
304      }
305    }
306    assert_eq!(enum_iterator::cardinality::<Myenum4>(), 1);
307    assert_eq!(Into::<usize>::into (Myenum4::X), 0);
308    assert_eq!(Some (Myenum4::X), Myenum4::from_usize (0));
309    assert_eq!(None, Myenum4::from_usize (1));
310    assert_eq!(Some (0), Myenum4::X.to_usize());
311    assert_eq!(enum_iterator::first::<Myenum4>().unwrap(), Myenum4::X);
312    assert_eq!(enum_iterator::last::<Myenum4>().unwrap(), Myenum4::X);
313    let mut i = enum_iterator::all::<Myenum4>();
314    assert_eq!(i.next(), Some (Myenum4::X));
315    assert_eq!(i.next(), None);
316    assert_eq!(enum_iterator::next (&Myenum4::X), None);
317    assert_eq!(enum_iterator::previous (&Myenum4::X), None);
318
319    // private nullary enum
320    enum_unitary!{
321      #[derive(Debug, PartialEq)]
322      enum Myenum5 { }
323    }
324    assert_eq!(enum_iterator::cardinality::<Myenum5>(), 0);
325    assert_eq!(None, Myenum5::from_usize (0));
326    assert_eq!(enum_iterator::first::<Myenum5>(), None);
327    assert_eq!(enum_iterator::last::<Myenum5>(), None);
328    let mut i = enum_iterator::all::<Myenum5>();
329    assert_eq!(i.next(), None);
330
331    // public nullary enum
332    enum_unitary!{
333      #[derive(Debug, PartialEq)]
334      pub enum Myenum6 { }
335    }
336    assert_eq!(enum_iterator::cardinality::<Myenum6>(), 0);
337    assert_eq!(None, Myenum6::from_usize (0));
338    assert_eq!(enum_iterator::first::<Myenum6>(), None);
339    assert_eq!(enum_iterator::last::<Myenum6>(), None);
340    let mut i = enum_iterator::all::<Myenum6>();
341    assert_eq!(i.next(), None);
342  }
343} // end mod tests