1 #![cfg_attr(all(test, feature = "i128"), feature(i128, i128_type))]
3 //! A library for defining enums that can be used in compact bit sets.
5 //! It supports enums up to 64 variants on stable Rust, and up to 128 variants on nightly Rust with
6 //! the `i128` feature enabled.
8 //! # Defining enums for use with EnumSet
10 //! Enums to be used with [`EnumSet`] should be defined through the [`enum_set_type!`] macro:
13 //! # #[macro_use] extern crate enumset;
16 //! /// Documentation for the enum
18 //! A, B, C, D, E, F, G,
19 //! #[doc(hidden)] __NonExhaustive,
25 //! # Working with EnumSets
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:
31 //! # #[macro_use] extern crate enumset;
33 //! # enum_set_type! {
35 //! # A, B, C, D, E, F, G,
39 //! let new_set = Enum::A | Enum::C | Enum::G;
40 //! assert_eq!(new_set.len(), 3);
44 //! The [`enum_set!`] macro also allows you to create constant EnumSets:
47 //! # #[macro_use] extern crate enumset;
49 //! # enum_set_type! {
50 //! # enum Enum { A, B, C }
53 //! const CONST_SET: EnumSet<Enum> = enum_set!(Enum, Enum::A | Enum::B);
54 //! assert_eq!(CONST_SET, Enum::A | Enum::B);
58 //! Mutable operations on the [`EnumSet`] otherwise work basically as expected:
61 //! # #[macro_use] extern crate enumset;
63 //! # enum_set_type! {
65 //! # A, B, C, D, E, F, G,
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);
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
84 use std::fmt::{Debug, Formatter};
89 pub trait EnumSetType : Copy {
90 type Repr: Shl<u8, Output = Self::Repr> + Eq + Not<Output = Self::Repr> +
91 Sub<Output = Self::Repr> + BitOr<Output = Self::Repr> +
92 BitAnd<Output = Self::Repr> + BitXor<Output = Self::Repr> +
93 BitOrAssign + BitAndAssign + Copy + Debug + Ord + Eq + Hash;
94 const ZERO: Self::Repr;
95 const ONE : Self::Repr;
96 const VARIANT_COUNT: u8;
98 fn count_ones(val: Self::Repr) -> usize;
99 fn into_u8(self) -> u8;
100 fn from_u8(val: u8) -> Self;
103 /// An efficient set type for enums created with the [`enum_set_type!`](./macro.enum_set_type.html)
105 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
106 pub struct EnumSet<T : EnumSetType>(#[doc(hidden)] pub T::Repr);
107 impl <T : EnumSetType> EnumSet<T> {
108 fn mask(bit: u8) -> T::Repr {
111 fn has_bit(&self, bit: u8) -> bool {
112 let mask = Self::mask(bit);
113 self.0 & mask == mask
116 /// Returns an empty set.
117 pub fn new() -> Self {
121 /// Returns the number of values in this set.
122 pub fn len(&self) -> usize {
123 T::count_ones(self.0)
125 /// Checks if the set is empty.
126 pub fn is_empty(&self) -> bool {
129 /// Removes all elements from the set.
130 pub fn clear(&mut self) {
134 /// Checks if this set shares no elements with another.
135 pub fn is_disjoint(&self, other: Self) -> bool {
136 self.0 & other.0 == T::ZERO
138 /// Checks if all elements in another set are in this set.
139 pub fn is_superset(&self, other: Self) -> bool {
140 other.0 & self.0 == other.0
142 /// Checks if all elements of this set are in another set.
143 pub fn is_subset(&self, other: Self) -> bool {
144 other.is_superset(*self)
147 /// Returns a set containing the union of all elements in both sets.
148 pub fn union(&self, other: Self) -> Self {
149 EnumSet(self.0 | other.0)
151 /// Returns a set containing all elements in common with another set.
152 pub fn intersection(&self, other: Self) -> Self {
153 EnumSet(self.0 & other.0)
155 /// Returns a set with all elements of the other set removed.
156 pub fn difference(&self, other: Self) -> Self {
157 EnumSet(self.0 & !other.0)
159 /// Returns a set with all elements not contained in both sets.
160 pub fn symmetrical_difference(&self, other: Self) -> Self {
161 EnumSet(self.0 ^ other.0)
164 /// Checks whether this set contains a value.
165 pub fn contains(&self, value: T) -> bool {
166 self.has_bit(value.into_u8())
168 /// Adds a value to this set.
169 pub fn insert(&mut self, value: T) -> bool {
170 let contains = self.contains(value);
171 self.0 |= Self::mask(value.into_u8());
174 /// Removes a value from this set.
175 pub fn remove(&mut self, value: T) -> bool {
176 let contains = self.contains(value);
177 self.0 &= !Self::mask(value.into_u8());
181 /// Adds all elements in another set to this one.
182 pub fn insert_all(&mut self, other: Self) {
185 /// Removes all values in another set from this one.
186 pub fn remove_all(&mut self, other: Self) {
190 pub fn iter(&self) -> EnumSetIter<T> {
191 EnumSetIter(*self, 0)
194 impl <T : EnumSetType> IntoIterator for EnumSet<T> {
196 type IntoIter = EnumSetIter<T>;
198 fn into_iter(self) -> Self::IntoIter {
202 impl <T : EnumSetType> Sub<EnumSet<T>> for EnumSet<T> {
204 fn sub(self, other: Self) -> Self::Output {
205 self.difference(other)
208 impl <T : EnumSetType> BitAnd<EnumSet<T>> for EnumSet<T> {
210 fn bitand(self, other: Self) -> Self::Output {
211 self.intersection(other)
214 impl <T : EnumSetType> BitOr<EnumSet<T>> for EnumSet<T> {
216 fn bitor(self, other: Self) -> Self::Output {
220 impl <T : EnumSetType> BitXor<EnumSet<T>> for EnumSet<T> {
222 fn bitxor(self, other: Self) -> Self::Output {
223 self.symmetrical_difference(other)
226 impl <T : EnumSetType> BitOr<T> for EnumSet<T> {
228 fn bitor(self, other: T) -> Self::Output {
229 EnumSet(self.0 | Self::mask(other.into_u8()))
233 impl <T : EnumSetType + Debug> Debug for EnumSet<T> {
234 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
235 let mut is_first = true;
236 f.write_str("EnumSet(")?;
237 for v in self.iter() {
238 if !is_first { f.write_str(" | ")?; }
247 /// The iterator used by [`EnumSet`](./struct.EnumSet.html).
248 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
249 pub struct EnumSetIter<T : EnumSetType>(EnumSet<T>, u8);
250 impl <T : EnumSetType> Iterator for EnumSetIter<T> {
253 fn next(&mut self) -> Option<Self::Item> {
254 while self.1 < T::VARIANT_COUNT {
257 if self.0.has_bit(bit) {
258 return Some(T::from_u8(bit))
263 fn size_hint(&self) -> (usize, Option<usize>) {
264 let left = T::count_ones((self.0).0 & !((T::ONE << self.1) - T::ONE));
271 #[cfg(feature = "i128")]
272 macro_rules! enum_set_type_internal_count_variants {
273 ($next:ident ($($args:tt)*)
274 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
275 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
276 $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
277 $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
278 $_40:ident $_41:ident $_42:ident $_43:ident $_44:ident $_45:ident $_46:ident $_47:ident
279 $_50:ident $_51:ident $_52:ident $_53:ident $_54:ident $_55:ident $_56:ident $_57:ident
280 $_60:ident $_61:ident $_62:ident $_63:ident $_64:ident $_65:ident $_66:ident $_67:ident
281 $_70:ident $_71:ident $_72:ident $_73:ident $_74:ident $_75:ident $_76:ident $_77:ident
282 $_80:ident $_81:ident $_82:ident $_83:ident $_84:ident $_85:ident $_86:ident $_87:ident
283 $_90:ident $_91:ident $_92:ident $_93:ident $_94:ident $_95:ident $_96:ident $_97:ident
284 $_a0:ident $_a1:ident $_a2:ident $_a3:ident $_a4:ident $_a5:ident $_a6:ident $_a7:ident
285 $_b0:ident $_b1:ident $_b2:ident $_b3:ident $_b4:ident $_b5:ident $_b6:ident $_b7:ident
286 $_c0:ident $_c1:ident $_c2:ident $_c3:ident $_c4:ident $_c5:ident $_c6:ident $_c7:ident
287 $_d0:ident $_d1:ident $_d2:ident $_d3:ident $_d4:ident $_d5:ident $_d6:ident $_d7:ident
288 $_e0:ident $_e1:ident $_e2:ident $_e3:ident $_e4:ident $_e5:ident $_e6:ident $_e7:ident
289 $_f0:ident $_f1:ident $_f2:ident $_f3:ident $_f4:ident $_f5:ident $_f6:ident $_f7:ident
292 ENUM_SET___TOO_MANY_ENUM_VARIANTS___MAX_IS_128
294 ($next:ident ($($args:tt)*)
295 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
296 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
297 $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
298 $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
299 $_40:ident $_41:ident $_42:ident $_43:ident $_44:ident $_45:ident $_46:ident $_47:ident
300 $_50:ident $_51:ident $_52:ident $_53:ident $_54:ident $_55:ident $_56:ident $_57:ident
301 $_60:ident $_61:ident $_62:ident $_63:ident $_64:ident $_65:ident $_66:ident $_67:ident
302 $_70:ident $_71:ident $_72:ident $_73:ident $_74:ident $_75:ident $_76:ident $_77:ident
305 enum_set_type_internal! { @$next u128 $($args)* }
307 ($next:ident ($($args:tt)*)
308 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
309 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
310 $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
311 $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
314 enum_set_type_internal! { @$next u64 $($args)* }
316 ($next:ident ($($args:tt)*)
317 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
318 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
321 enum_set_type_internal! { @$next u32 $($args)* }
323 ($next:ident ($($args:tt)*)
324 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
327 enum_set_type_internal! { @$next u16 $($args)* }
329 ($next:ident ($($args:tt)*) $($rest:ident)*) => {
330 enum_set_type_internal! { @$next u8 $($args)* }
336 #[cfg(not(feature = "i128"))]
337 macro_rules! enum_set_type_internal_count_variants {
338 ($next:ident ($($args:tt)*)
339 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
340 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
341 $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
342 $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
343 $_40:ident $_41:ident $_42:ident $_43:ident $_44:ident $_45:ident $_46:ident $_47:ident
344 $_50:ident $_51:ident $_52:ident $_53:ident $_54:ident $_55:ident $_56:ident $_57:ident
345 $_60:ident $_61:ident $_62:ident $_63:ident $_64:ident $_65:ident $_66:ident $_67:ident
346 $_70:ident $_71:ident $_72:ident $_73:ident $_74:ident $_75:ident $_76:ident $_77:ident
349 ENUM_SET___TOO_MANY_ENUM_VARIANTS___MAX_IS_64
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 $_20:ident $_21:ident $_22:ident $_23:ident $_24:ident $_25:ident $_26:ident $_27:ident
355 $_30:ident $_31:ident $_32:ident $_33:ident $_34:ident $_35:ident $_36:ident $_37:ident
358 enum_set_type_internal! { @$next u64 $($args)* }
360 ($next:ident ($($args:tt)*)
361 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
362 $_10:ident $_11:ident $_12:ident $_13:ident $_14:ident $_15:ident $_16:ident $_17:ident
365 enum_set_type_internal! { @$next u32 $($args)* }
367 ($next:ident ($($args:tt)*)
368 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
371 enum_set_type_internal! { @$next u16 $($args)* }
373 ($next:ident ($($args:tt)*) $($rest:ident)*) => {
374 enum_set_type_internal! { @$next u8 $($args)* }
380 macro_rules! enum_set_type_internal {
381 // Counting functions
382 (@ident ($($random:tt)*) $value:expr) => { $value };
383 (@count $($value:tt)*) => {
384 0u8 $(+ enum_set_type_internal!(@ident ($value) 1u8))*
388 (@body $repr:ident ($(#[$enum_attr:meta])*) ($($vis:tt)*) $enum_name:ident {
389 $($(#[$attr:meta])* $variant:ident,)*
391 $(#[$enum_attr])* #[repr(u8)]
392 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
393 $($vis)* enum $enum_name {
394 $($(#[$attr])* $variant,)*
396 impl $crate::EnumSetType for $enum_name {
398 const ZERO: Self::Repr = 0;
399 const ONE : Self::Repr = 1;
400 const VARIANT_COUNT: u8 = enum_set_type_internal!(@count $($variant)*);
402 fn count_ones(val: Self::Repr) -> usize {
403 val.count_ones() as usize
405 fn into_u8(self) -> u8 {
408 fn from_u8(val: u8) -> Self {
409 unsafe { ::std::mem::transmute(val) }
412 impl ::std::ops::BitOr<$enum_name> for $enum_name {
413 type Output = $crate::EnumSet<$enum_name>;
414 fn bitor(self, other: $enum_name) -> Self::Output {
415 enum_set!($enum_name, self | other)
421 /// Defines enums which can be used with EnumSet.
423 /// While attributes and documentation can be attached to the enums, the variants may not
429 /// # #[macro_use] extern crate enumset;
430 /// # use enumset::*;
433 /// A, B, C, D, E, F, G
436 /// /// Documentation
438 /// A, B, C, D, E, F, G,
439 /// #[doc(hidden)] __NonExhaustive,
445 macro_rules! enum_set_type {
446 ($(#[$enum_attr:meta])* pub enum $enum_name:ident {
447 $($(#[$attr:meta])* $variant:ident),* $(,)*
449 enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) (pub) $enum_name {
450 $($(#[$attr])* $variant,)*
452 enum_set_type!($($rest)*);
454 ($(#[$enum_attr:meta])* enum $enum_name:ident {
455 $($(#[$attr:meta])* $variant:ident),* $(,)*
457 enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) () $enum_name {
458 $($(#[$attr])* $variant,)*
460 enum_set_type!($($rest)*);
465 /// Creates a EnumSet literal, which can be used in const contexts.
467 /// The format is `enum_set_type!(Type, Type::A | Type::B | Type::C)`, where `Type` is the type
468 /// the enum will contain, and the rest is the variants that the set will contain.
473 /// # #[macro_use] extern crate enumset;
474 /// # use enumset::*;
475 /// # enum_set_type! {
476 /// # enum Enum { A, B, C }
479 /// const CONST_SET: EnumSet<Enum> = enum_set!(Enum, Enum::A | Enum::B);
480 /// assert_eq!(CONST_SET, Enum::A | Enum::B);
484 macro_rules! enum_set {
485 ($enum_name:ty, $($value:path)|* $(|)*) => {
486 $crate::EnumSet::<$enum_name>(
487 <$enum_name as $crate::EnumSetType>::ZERO
488 $(| (<$enum_name as $crate::EnumSetType>::ONE << ($value as u8)))*
500 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,
503 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,
507 #[cfg(feature = "i128")]
510 _00, _01, _02, _03, _04, _05, _06, _07,
511 _10, _11, _12, _13, _14, _15, _16, _17,
512 _20, _21, _22, _23, _24, _25, _26, _27,
513 _30, _31, _32, _33, _34, _35, _36, _37,
514 _40, _41, _42, _43, _44, _45, _46, _47,
515 _50, _51, _52, _53, _54, _55, _56, _57,
516 _60, _61, _62, _63, _64, _65, _66, _67,
517 _70, _71, _72, _73, _74, _75, _76, _77,
518 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,
522 macro_rules! test_variants {
523 ($enum_name:ident $test_name:ident $($variant:ident,)*) => {
526 let count = enum_set_type_internal!(@count u8 $($variant)*);
528 assert!(($enum_name::$variant as u8) < count);
534 test_variants! { Enum enum_variant_range_test
535 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,
538 #[cfg(feature = "i128")]
539 test_variants! { LargeEnum large_enum_variant_range_test
540 _00, _01, _02, _03, _04, _05, _06, _07,
541 _10, _11, _12, _13, _14, _15, _16, _17,
542 _20, _21, _22, _23, _24, _25, _26, _27,
543 _30, _31, _32, _33, _34, _35, _36, _37,
544 _40, _41, _42, _43, _44, _45, _46, _47,
545 _50, _51, _52, _53, _54, _55, _56, _57,
546 _60, _61, _62, _63, _64, _65, _66, _67,
547 _70, _71, _72, _73, _74, _75, _76, _77,
548 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,
551 macro_rules! test_enum {
552 ($e:ident, $m:ident) => {
556 const CONST_SET: EnumSet<$e> = enum_set!($e, $e::A | $e::Y);
557 const EMPTY_SET: EnumSet<$e> = enum_set!($e, );
560 assert_eq!(CONST_SET.len(), 2);
561 assert!(CONST_SET.contains($e::A));
562 assert!(CONST_SET.contains($e::Y));
563 assert!(EMPTY_SET.is_empty());
567 fn basic_add_remove() {
568 let mut set = EnumSet::new();
572 assert_eq!(set, $e::A | $e::B | $e::C);
574 assert_eq!(set, $e::A | $e::C);
576 assert_eq!(set, $e::A | $e::C | $e::D);
577 set.insert_all($e::F | $e::E | $e::G);
578 assert_eq!(set, $e::A | $e::C | $e::D | $e::F | $e::E | $e::G);
579 set.remove_all($e::A | $e::D | $e::G);
580 assert_eq!(set, $e::C | $e::F | $e::E);
581 assert!(!set.is_empty());
583 assert!(set.is_empty());
587 fn basic_iter_test() {
588 let mut set = EnumSet::new();
594 let mut set_2 = EnumSet::new();
595 let vec: Vec<$e> = set.iter().collect();
599 assert_eq!(set, set_2);
601 let mut set_3 = EnumSet::new();
605 assert_eq!(set, set_3);
609 fn basic_ops_test() {
610 assert_eq!(($e::A | $e::B) | ($e::B | $e::C), $e::A | $e::B | $e::C);
611 assert_eq!(($e::A | $e::B) & ($e::B | $e::C), EnumSet::new() | $e::B);
612 assert_eq!(($e::A | $e::B) ^ ($e::B | $e::C), $e::A | $e::C);
613 assert_eq!(($e::A | $e::B) - ($e::B | $e::C), EnumSet::new() | $e::A);
617 fn basic_set_status() {
618 assert!(($e::A | $e::B | $e::C).is_disjoint($e::D | $e::E | $e::F));
619 assert!(!($e::A | $e::B | $e::C | $e::D).is_disjoint($e::D | $e::E | $e::F));
620 assert!(($e::A | $e::B).is_subset($e::A | $e::B | $e::C));
621 assert!(!($e::A | $e::D).is_subset($e::A | $e::B | $e::C));
626 assert_eq!(format!("{:?}", $e::A | $e::B | $e::W), "EnumSet(A | B | W)");
632 test_enum!(Enum, small_enum);
633 #[cfg(feature = "i128")]
634 test_enum!(LargeEnum, large_enum);