]> git.lizzy.rs Git - enumset.git/blob - src/lib.rs
Remove depenency of the enum_set!(A | B | C) form on nightly features through black...
[enumset.git] / src / lib.rs
1 #![cfg_attr(not(test), no_std)]
2 #![cfg_attr(all(feature = "nightly"), feature(const_fn, allow_internal_unstable, macro_vis_matcher))]
3 #![forbid(missing_docs)]
4
5 //! A library for defining enums that can be used in compact bit sets. It supports enums up to 128
6 //! variants, and has a macro to use these sets in constants.
7 //!
8 //! # Defining enums for use with EnumSet
9 //!
10 //! Enums to be used with [`EnumSet`] should be defined through the [`enum_set_type!`] macro:
11 //!
12 //! ```rust
13 //! # #[macro_use] extern crate enumset;
14 //! # use enumset::*;
15 //! enum_set_type! {
16 //!     /// Documentation for the enum
17 //!     pub enum Enum {
18 //!         A, B, C, D, E, F, G,
19 //!         #[doc(hidden)] __NonExhaustive,
20 //!     }
21 //! }
22 //! # fn main() { }
23 //! ```
24 //!
25 //! # Working with EnumSets
26 //!
27 //! EnumSets can be constructed via [`EnumSet::new()`] like a normal set. In addition,
28 //! [`enum_set_type!`] creates operator overloads that allow you to create EnumSets like so:
29 //!
30 //! ```rust
31 //! # #[macro_use] extern crate enumset;
32 //! # use enumset::*;
33 //! # enum_set_type! {
34 //! #      pub enum Enum {
35 //! #        A, B, C, D, E, F, G,
36 //! #    }
37 //! # }
38 //! # fn main() {
39 //! let new_set = Enum::A | Enum::C | Enum::G;
40 //! assert_eq!(new_set.len(), 3);
41 //! # }
42 //! ```
43 //!
44 //! The [`enum_set!`] macro also allows you to create constant EnumSets:
45 //!
46 //! ```rust
47 //! # #[macro_use] extern crate enumset;
48 //! # use enumset::*;
49 //! # enum_set_type! {
50 //! #     enum Enum { A, B, C }
51 //! # }
52 //! # fn main() {
53 //! const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
54 //! assert_eq!(CONST_SET, Enum::A | Enum::B);
55 //! # }
56 //! ```
57 //!
58 //! Mutable operations on the [`EnumSet`] otherwise work basically as expected:
59 //!
60 //! ```rust
61 //! # #[macro_use] extern crate enumset;
62 //! # use enumset::*;
63 //! # enum_set_type! {
64 //! #      pub enum Enum {
65 //! #        A, B, C, D, E, F, G,
66 //! #    }
67 //! # }
68 //! # fn main() {
69 //! let mut set = EnumSet::new();
70 //! set.insert(Enum::A);
71 //! set.insert_all(Enum::E | Enum::G);
72 //! assert!(set.contains(Enum::A));
73 //! assert!(!set.contains(Enum::B));
74 //! assert_eq!(set, Enum::A | Enum::E | Enum::G);
75 //! # }
76 //! ```
77 //!
78 //! [`EnumSet`]: ./struct.EnumSet.html
79 //! [`EnumSet::new()`]: ./struct.EnumSet.html#method.new
80 //! [`enum_set!`]: ./macro.enum_set.html
81 //! [`enum_set_type!`]: ./macro.enum_set_type.html
82
83 #[cfg(test)]
84 extern crate core;
85
86 use core::fmt;
87 use core::fmt::{Debug, Formatter};
88 use core::hash::Hash;
89 use core::ops::*;
90
91 #[doc(hidden)]
92 pub trait EnumSetType : Copy {
93     type Repr: Shl<u8, Output = Self::Repr> + Eq + Not<Output = Self::Repr> +
94                Sub<Output = Self::Repr> + BitOr<Output = Self::Repr> +
95                BitAnd<Output = Self::Repr> + BitXor<Output = Self::Repr> +
96                BitOrAssign + BitAndAssign + Copy + Debug + Ord + Eq + Hash;
97     const ZERO: Self::Repr;
98     const ONE : Self::Repr;
99     const VARIANT_COUNT: u8;
100
101     fn count_ones(val: Self::Repr) -> usize;
102     fn into_u8(self) -> u8;
103     fn from_u8(val: u8) -> Self;
104
105     fn repr_to_u128(bits: Self::Repr) -> u128;
106     fn repr_from_u128(bits: u128) -> Self::Repr;
107 }
108
109 #[doc(hidden)]
110 pub struct EnumSetSameTypeHack<'a, T: EnumSetType + 'static> {
111     pub unified: &'a [T],
112     pub enum_set: EnumSet<T>,
113 }
114
115 /// An efficient set type for enums created with the [`enum_set_type!`](./macro.enum_set_type.html)
116 /// macro.
117 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
118 pub struct EnumSet<T : EnumSetType> { 
119     #[doc(hidden)] pub __enumset_underlying: T::Repr
120 }
121 impl <T : EnumSetType> EnumSet<T> {
122     fn mask(bit: u8) -> T::Repr {
123         T::ONE << bit
124     }
125     fn has_bit(&self, bit: u8) -> bool {
126         let mask = Self::mask(bit);
127         self.__enumset_underlying & mask == mask
128     }
129
130     /// Returns an empty set.
131     #[cfg(not(feature = "nightly"))]
132     pub fn new() -> Self {
133         EnumSet { __enumset_underlying: T::ZERO }
134     }
135     /// Returns an empty set.
136     #[cfg(feature = "nightly")]
137     pub const fn new() -> Self {
138         EnumSet { __enumset_underlying: T::ZERO }
139     }
140
141     /// Total number of bits this enumset uses. Note that the actual amount of space used is
142     /// rounded up to the next highest integer type (`u8`, `u16`, `u32`, `u64`, or `u128`).
143     pub fn bit_width() -> u8 {
144         T::VARIANT_COUNT as u8
145     }
146
147     /// Returns the raw bits of this set
148     pub fn to_bits(&self) -> u128 {
149         T::repr_to_u128(self.__enumset_underlying)
150     }
151     /// Constructs a bitset from raw bits
152     pub fn from_bits(bits: u128) -> Self {
153         EnumSet { __enumset_underlying: T::repr_from_u128(bits) }
154     }
155
156     /// Returns the number of values in this set.
157     pub fn len(&self) -> usize {
158         T::count_ones(self.__enumset_underlying)
159     }
160     /// Checks if the set is empty.
161     pub fn is_empty(&self) -> bool {
162         self.__enumset_underlying == T::ZERO
163     }
164     /// Removes all elements from the set.
165     pub fn clear(&mut self) {
166         self.__enumset_underlying = T::ZERO
167     }
168
169     /// Checks if this set shares no elements with another.
170     pub fn is_disjoint(&self, other: Self) -> bool {
171         self.__enumset_underlying & other.__enumset_underlying == T::ZERO
172     }
173     /// Checks if all elements in another set are in this set.
174     pub fn is_superset(&self, other: Self) -> bool {
175         other.__enumset_underlying & self.__enumset_underlying == other.__enumset_underlying
176     }
177     /// Checks if all elements of this set are in another set.
178     pub fn is_subset(&self, other: Self) -> bool {
179         other.is_superset(*self)
180     }
181
182     /// Returns a set containing the union of all elements in both sets.
183     pub fn union(&self, other: Self) -> Self {
184         EnumSet { __enumset_underlying: self.__enumset_underlying | other.__enumset_underlying }
185     }
186     /// Returns a set containing all elements in common with another set.
187     pub fn intersection(&self, other: Self) -> Self {
188         EnumSet { __enumset_underlying: self.__enumset_underlying & other.__enumset_underlying }
189     }
190     /// Returns a set with all elements of the other set removed.
191     pub fn difference(&self, other: Self) -> Self {
192         EnumSet { __enumset_underlying: self.__enumset_underlying & !other.__enumset_underlying }
193     }
194     /// Returns a set with all elements not contained in both sets.
195     pub fn symmetrical_difference(&self, other: Self) -> Self {
196         EnumSet { __enumset_underlying: self.__enumset_underlying ^ other.__enumset_underlying }
197     }
198
199     /// Checks whether this set contains a value.
200     pub fn contains(&self, value: T) -> bool {
201         self.has_bit(value.into_u8())
202     }
203     /// Adds a value to this set.
204     pub fn insert(&mut self, value: T) -> bool {
205         let contains = self.contains(value);
206         self.__enumset_underlying |= Self::mask(value.into_u8());
207         contains
208     }
209     /// Removes a value from this set.
210     pub fn remove(&mut self, value: T) -> bool {
211         let contains = self.contains(value);
212         self.__enumset_underlying &= !Self::mask(value.into_u8());
213         contains
214     }
215
216     /// Adds all elements in another set to this one.
217     pub fn insert_all(&mut self, other: Self) {
218         self.__enumset_underlying |= other.__enumset_underlying
219     }
220     /// Removes all values in another set from this one.
221     pub fn remove_all(&mut self, other: Self) {
222         self.__enumset_underlying &= !other.__enumset_underlying
223     }
224
225     /// Creates an iterator over the values in this set.
226     pub fn iter(&self) -> EnumSetIter<T> {
227         EnumSetIter(*self, 0)
228     }
229 }
230 impl <T : EnumSetType> IntoIterator for EnumSet<T> {
231     type Item = T;
232     type IntoIter = EnumSetIter<T>;
233
234     fn into_iter(self) -> Self::IntoIter {
235         self.iter()
236     }
237 }
238 impl <T : EnumSetType> Sub<EnumSet<T>> for EnumSet<T> {
239     type Output = Self;
240     fn sub(self, other: Self) -> Self::Output {
241         self.difference(other)
242     }
243 }
244 impl <T : EnumSetType> BitAnd<EnumSet<T>> for EnumSet<T> {
245     type Output = Self;
246     fn bitand(self, other: Self) -> Self::Output {
247         self.intersection(other)
248     }
249 }
250 impl <T : EnumSetType> BitOr<EnumSet<T>> for EnumSet<T> {
251     type Output = Self;
252     fn bitor(self, other: Self) -> Self::Output {
253         self.union(other)
254     }
255 }
256 impl <T : EnumSetType> BitXor<EnumSet<T>> for EnumSet<T> {
257     type Output = Self;
258     fn bitxor(self, other: Self) -> Self::Output {
259         self.symmetrical_difference(other)
260     }
261 }
262 impl <T : EnumSetType> BitOr<T> for EnumSet<T> {
263     type Output = Self;
264     fn bitor(self, other: T) -> Self::Output {
265         EnumSet { __enumset_underlying: self.__enumset_underlying | Self::mask(other.into_u8()) }
266     }
267 }
268
269 impl <T : EnumSetType + Debug> Debug for EnumSet<T> {
270     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
271         let mut is_first = true;
272         f.write_str("EnumSet(")?;
273         for v in self.iter() {
274             if !is_first { f.write_str(" | ")?; }
275             is_first = false;
276             v.fmt(f)?;
277         }
278         f.write_str(")")?;
279         Ok(())
280     }
281 }
282
283 /// The iterator used by [`EnumSet`](./struct.EnumSet.html).
284 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
285 pub struct EnumSetIter<T : EnumSetType>(EnumSet<T>, u8);
286 impl <T : EnumSetType> Iterator for EnumSetIter<T> {
287     type Item = T;
288
289     fn next(&mut self) -> Option<Self::Item> {
290         while self.1 < T::VARIANT_COUNT {
291             let bit = self.1;
292             self.1 += 1;
293             if self.0.has_bit(bit) {
294                 return Some(T::from_u8(bit))
295             }
296         }
297         None
298     }
299     fn size_hint(&self) -> (usize, Option<usize>) {
300         let left = T::count_ones((self.0).__enumset_underlying & !((T::ONE << self.1) - T::ONE));
301         (left, Some(left))
302     }
303 }
304
305 #[macro_export]
306 #[doc(hidden)]
307 macro_rules! enum_set_type_internal_count_variants {
308     ($next:ident ($($args:tt)*)
309         $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
310         $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
311         $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
312         $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
313         $_40:ident $_41:ident $_42:ident $_43:ident $_44:ident $_45:ident $_46:ident $_47:ident
314         $_50:ident $_51:ident $_52:ident $_53:ident $_54:ident $_55:ident $_56:ident $_57:ident
315         $_60:ident $_61:ident $_62:ident $_63:ident $_64:ident $_65:ident $_66:ident $_67:ident
316         $_70:ident $_71:ident $_72:ident $_73:ident $_74:ident $_75:ident $_76:ident $_77:ident
317         $_80:ident $_81:ident $_82:ident $_83:ident $_84:ident $_85:ident $_86:ident $_87:ident
318         $_90:ident $_91:ident $_92:ident $_93:ident $_94:ident $_95:ident $_96:ident $_97:ident
319         $_a0:ident $_a1:ident $_a2:ident $_a3:ident $_a4:ident $_a5:ident $_a6:ident $_a7:ident
320         $_b0:ident $_b1:ident $_b2:ident $_b3:ident $_b4:ident $_b5:ident $_b6:ident $_b7:ident
321         $_c0:ident $_c1:ident $_c2:ident $_c3:ident $_c4:ident $_c5:ident $_c6:ident $_c7:ident
322         $_d0:ident $_d1:ident $_d2:ident $_d3:ident $_d4:ident $_d5:ident $_d6:ident $_d7:ident
323         $_e0:ident $_e1:ident $_e2:ident $_e3:ident $_e4:ident $_e5:ident $_e6:ident $_e7:ident
324         $_f0:ident $_f1:ident $_f2:ident $_f3:ident $_f4:ident $_f5:ident $_f6:ident $_f7:ident
325         $($rest:ident)+
326     ) => {
327         compile_error!("enum_set_type! can only accept up to 128 variants.")
328     };
329     ($next:ident ($($args:tt)*)
330         $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
331         $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
332         $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
333         $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
334         $_40:ident $_41:ident $_42:ident $_43:ident $_44:ident $_45:ident $_46:ident $_47:ident
335         $_50:ident $_51:ident $_52:ident $_53:ident $_54:ident $_55:ident $_56:ident $_57:ident
336         $_60:ident $_61:ident $_62:ident $_63:ident $_64:ident $_65:ident $_66:ident $_67:ident
337         $_70:ident $_71:ident $_72:ident $_73:ident $_74:ident $_75:ident $_76:ident $_77:ident
338         $($rest:ident)+
339     ) => {
340         enum_set_type_internal! { @$next u128 $($args)* }
341     };
342     ($next:ident ($($args:tt)*)
343         $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
344         $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
345         $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
346         $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
347         $($rest:ident)+
348     ) => {
349         enum_set_type_internal! { @$next u64 $($args)* }
350     };
351     ($next:ident ($($args:tt)*)
352         $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
353         $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
354         $($rest:ident)+
355     ) => {
356         enum_set_type_internal! { @$next u32 $($args)* }
357     };
358     ($next:ident ($($args:tt)*)
359         $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
360         $($rest:ident)+
361     ) => {
362         enum_set_type_internal! { @$next u16 $($args)* }
363     };
364     ($next:ident ($($args:tt)*) $($rest:ident)*) => {
365         enum_set_type_internal! { @$next u8 $($args)* }
366     };
367 }
368
369 #[macro_export]
370 #[doc(hidden)]
371 macro_rules! enum_set_type_internal {
372     // Counting functions
373     (@ident ($($random:tt)*) $value:expr) => { $value };
374     (@count $($value:tt)*) => {
375         0u8 $(+ enum_set_type_internal!(@ident ($value) 1u8))*
376     };
377
378     // Codegen
379     (@body $repr:ident ($(#[$enum_attr:meta])*) ($($vis:tt)*) $enum_name:ident {
380         $($(#[$attr:meta])* $variant:ident,)*
381     }) => {
382         $(#[$enum_attr])* #[repr(u8)]
383         #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
384         $($vis)* enum $enum_name {
385             $($(#[$attr])* $variant,)*
386         }
387         impl $crate::EnumSetType for $enum_name {
388             type Repr = $repr;
389             const ZERO: Self::Repr = 0;
390             const ONE : Self::Repr = 1;
391             const VARIANT_COUNT: u8 = enum_set_type_internal!(@count $($variant)*);
392
393             fn count_ones(val: Self::Repr) -> usize {
394                 val.count_ones() as usize
395             }
396             fn into_u8(self) -> u8 {
397                 self as u8
398             }
399             fn from_u8(val: u8) -> Self {
400                 unsafe { ::std::mem::transmute(val) }
401             }
402
403             fn repr_to_u128(bits: Self::Repr) -> u128 {
404                 bits as u128
405             }
406             fn repr_from_u128(bits: u128) -> Self::Repr {
407                 bits as $repr
408             }
409         }
410         impl ::std::ops::BitOr<$enum_name> for $enum_name {
411             type Output = $crate::EnumSet<$enum_name>;
412             fn bitor(self, other: $enum_name) -> Self::Output {
413                 enum_set!($enum_name, self | other)
414             }
415         }
416     };
417 }
418
419 /// Defines enums which can be used with EnumSet.
420 ///
421 /// While attributes and documentation can be attached to the enums, the variants may not
422 /// contain data.
423 ///
424 /// # Examples
425 ///
426 /// ```rust
427 /// # #[macro_use] extern crate enumset;
428 /// # use enumset::*;
429 /// enum_set_type! {
430 ///     enum Enum {
431 ///         A, B, C, D, E, F, G
432 ///     }
433 ///
434 ///     /// Documentation
435 ///     pub enum Enum2 {
436 ///         A, B, C, D, E, F, G,
437 ///         #[doc(hidden)] __NonExhaustive,
438 ///     }
439 /// }
440 /// # fn main() { }
441 /// ```
442 #[macro_export]
443 #[cfg(not(feature = "nightly"))]
444 macro_rules! enum_set_type {
445     ($(#[$enum_attr:meta])* pub enum $enum_name:ident {
446         $($(#[$attr:meta])* $variant:ident),* $(,)*
447     } $($rest:tt)*) => {
448         enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) (pub) $enum_name {
449             $($(#[$attr])* $variant,)*
450         }) $($variant)*);
451         enum_set_type!($($rest)*);
452     };
453     ($(#[$enum_attr:meta])* enum $enum_name:ident {
454         $($(#[$attr:meta])* $variant:ident),* $(,)*
455     } $($rest:tt)*) => {
456         enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) () $enum_name {
457             $($(#[$attr])* $variant,)*
458         }) $($variant)*);
459         enum_set_type!($($rest)*);
460     };
461     () => { };
462 }
463
464 /// Defines enums which can be used with EnumSet.
465 ///
466 /// While attributes and documentation can be attached to the enums, the variants may not
467 /// contain data.
468 ///
469 /// # Examples
470 ///
471 /// ```rust
472 /// # #[macro_use] extern crate enumset;
473 /// # use enumset::*;
474 /// enum_set_type! {
475 ///     enum Enum {
476 ///         A, B, C, D, E, F, G
477 ///     }
478 ///
479 ///     /// Documentation
480 ///     pub enum Enum2 {
481 ///         A, B, C, D, E, F, G,
482 ///         #[doc(hidden)] __NonExhaustive,
483 ///     }
484 /// }
485 /// # fn main() { }
486 /// ```
487 #[macro_export]
488 #[cfg(feature = "nightly")]
489 #[allow_internal_unstable]
490 macro_rules! enum_set_type {
491     ($(#[$enum_attr:meta])* $vis:vis enum $enum_name:ident {
492         $($(#[$attr:meta])* $variant:ident),* $(,)*
493     } $($rest:tt)*) => {
494         enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) ($vis) $enum_name {
495             $($(#[$attr])* $variant,)*
496         }) $($variant)*);
497         enum_set_type!($($rest)*);
498     };
499     () => { };
500 }
501
502 /// Creates a EnumSet literal, which can be used in const contexts. The format used is
503 /// `enum_set!(Type::A | Type::B | Type::C)` Each variant must be of the same type, or
504 /// a error will occur at compile-time.
505 ///
506 /// You may also explicitly state the type of the variants that follow, as in
507 /// `enum_set!(Type, Type::A | Type::B | Type::C)`.
508 ///
509 /// # Examples
510 ///
511 /// ```rust
512 /// # #[macro_use] extern crate enumset;
513 /// # use enumset::*;
514 /// # enum_set_type! {
515 /// #     enum Enum { A, B, C }
516 /// # }
517 /// # fn main() {
518 /// const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
519 /// assert_eq!(CONST_SET, Enum::A | Enum::B);
520 ///
521 /// const EXPLICIT_CONST_SET: EnumSet<Enum> = enum_set!(Enum, Enum::A | Enum::B);
522 /// assert_eq!(EXPLICIT_CONST_SET, Enum::A | Enum::B);
523 /// # }
524 /// ```
525 ///
526 /// This macro is strongly typed. For example, the following will not compile:
527 ///
528 /// ```compile_fail
529 /// # #[macro_use] extern crate enumset;
530 /// # use enumset::*;
531 /// # enum_set_type! {
532 /// #     enum Enum { A, B, C }
533 /// #     enum Enum2 { A, B, C }
534 /// # }
535 /// # fn main() {
536 /// let type_error = enum_set!(Enum::A | Enum2::B);
537 /// # }
538 /// ```
539 #[macro_export]
540 macro_rules! enum_set {
541     () => { EnumSet::new() };
542     ($($value:path)|* $(|)*) => {
543         $crate::EnumSetSameTypeHack {
544             unified: &[$($value,)*],
545             enum_set: $crate::EnumSet {
546                 __enumset_underlying: 0 $(| (1 << ($value as u8)))*
547             },
548         }.enum_set
549     };
550     ($enum_name:ty, $($value:path)|* $(|)*) => {
551         $crate::EnumSet::<$enum_name> {
552             __enumset_underlying: 0 $(| (1 << ($value as $enum_name as u8)))*
553         }
554     }
555 }
556
557 #[cfg(test)]
558 #[allow(dead_code)]
559 mod test {
560     use super::*;
561
562     enum_set_type! {
563         enum Enum {
564             A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
565         }
566         enum Enum2 {
567             A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
568         }
569     }
570
571     enum_set_type! {
572         enum LargeEnum {
573             _00,  _01,  _02,  _03,  _04,  _05,  _06,  _07,
574             _10,  _11,  _12,  _13,  _14,  _15,  _16,  _17,
575             _20,  _21,  _22,  _23,  _24,  _25,  _26,  _27,
576             _30,  _31,  _32,  _33,  _34,  _35,  _36,  _37,
577             _40,  _41,  _42,  _43,  _44,  _45,  _46,  _47,
578             _50,  _51,  _52,  _53,  _54,  _55,  _56,  _57,
579             _60,  _61,  _62,  _63,  _64,  _65,  _66,  _67,
580             _70,  _71,  _72,  _73,  _74,  _75,  _76,  _77,
581             A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
582         }
583     }
584
585     macro_rules! test_variants {
586         ($enum_name:ident $test_name:ident $($variant:ident,)*) => {
587             #[test]
588             fn $test_name() {
589                 let count = enum_set_type_internal!(@count u8 $($variant)*);
590                 $(
591                     assert!(($enum_name::$variant as u8) < count);
592                 )*
593             }
594         }
595     }
596
597     test_variants! { Enum enum_variant_range_test
598         A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
599     }
600
601     test_variants! { LargeEnum large_enum_variant_range_test
602         _00,  _01,  _02,  _03,  _04,  _05,  _06,  _07,
603         _10,  _11,  _12,  _13,  _14,  _15,  _16,  _17,
604         _20,  _21,  _22,  _23,  _24,  _25,  _26,  _27,
605         _30,  _31,  _32,  _33,  _34,  _35,  _36,  _37,
606         _40,  _41,  _42,  _43,  _44,  _45,  _46,  _47,
607         _50,  _51,  _52,  _53,  _54,  _55,  _56,  _57,
608         _60,  _61,  _62,  _63,  _64,  _65,  _66,  _67,
609         _70,  _71,  _72,  _73,  _74,  _75,  _76,  _77,
610         A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
611     }
612
613     macro_rules! test_enum {
614         ($e:ident, $m:ident) => {
615             mod $m {
616                 use super::*;
617
618                 const CONST_SET: EnumSet<$e> = enum_set!($e, $e::A | $e::Y);
619                 const EMPTY_SET: EnumSet<$e> = enum_set!($e, );
620                 #[test]
621                 fn const_set() {
622                     assert_eq!(CONST_SET.len(), 2);
623                     assert!(CONST_SET.contains($e::A));
624                     assert!(CONST_SET.contains($e::Y));
625                     assert!(EMPTY_SET.is_empty());
626                 }
627
628                 #[test]
629                 fn basic_add_remove() {
630                     let mut set = EnumSet::new();
631                     set.insert($e::A);
632                     set.insert($e::B);
633                     set.insert($e::C);
634                     assert_eq!(set, $e::A | $e::B | $e::C);
635                     set.remove($e::B);
636                     assert_eq!(set, $e::A | $e::C);
637                     set.insert($e::D);
638                     assert_eq!(set, $e::A | $e::C | $e::D);
639                     set.insert_all($e::F | $e::E | $e::G);
640                     assert_eq!(set, $e::A | $e::C | $e::D | $e::F | $e::E | $e::G);
641                     set.remove_all($e::A | $e::D | $e::G);
642                     assert_eq!(set, $e::C | $e::F | $e::E);
643                     assert!(!set.is_empty());
644                     set.clear();
645                     assert!(set.is_empty());
646                 }
647
648                 #[test]
649                 fn basic_iter_test() {
650                     let mut set = EnumSet::new();
651                     set.insert($e::A);
652                     set.insert($e::B);
653                     set.insert($e::C);
654                     set.insert($e::E);
655
656                     let mut set_2 = EnumSet::new();
657                     let vec: Vec<$e> = set.iter().collect();
658                     for val in vec {
659                         set_2.insert(val);
660                     }
661                     assert_eq!(set, set_2);
662
663                     let mut set_3 = EnumSet::new();
664                     for val in set {
665                         set_3.insert(val);
666                     }
667                     assert_eq!(set, set_3);
668                 }
669
670                 #[test]
671                 fn basic_ops_test() {
672                     assert_eq!(($e::A | $e::B) | ($e::B | $e::C), $e::A | $e::B | $e::C);
673                     assert_eq!(($e::A | $e::B) & ($e::B | $e::C), EnumSet::new() | $e::B);
674                     assert_eq!(($e::A | $e::B) ^ ($e::B | $e::C), $e::A | $e::C);
675                     assert_eq!(($e::A | $e::B) - ($e::B | $e::C), EnumSet::new() | $e::A);
676                 }
677
678                 #[test]
679                 fn basic_set_status() {
680                     assert!(($e::A | $e::B | $e::C).is_disjoint($e::D | $e::E | $e::F));
681                     assert!(!($e::A | $e::B | $e::C | $e::D).is_disjoint($e::D | $e::E | $e::F));
682                     assert!(($e::A | $e::B).is_subset($e::A | $e::B | $e::C));
683                     assert!(!($e::A | $e::D).is_subset($e::A | $e::B | $e::C));
684                 }
685
686                 #[test]
687                 fn debug_impl() {
688                     assert_eq!(format!("{:?}", $e::A | $e::B | $e::W), "EnumSet(A | B | W)");
689                 }
690             }
691         }
692     }
693
694     test_enum!(Enum, small_enum);
695     test_enum!(LargeEnum, large_enum);
696 }