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)]
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.
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::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
87 use core::fmt::{Debug, Formatter};
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;
101 fn count_ones(val: Self::Repr) -> usize;
102 fn into_u8(self) -> u8;
103 fn from_u8(val: u8) -> Self;
105 fn repr_to_u128(bits: Self::Repr) -> u128;
106 fn repr_from_u128(bits: u128) -> Self::Repr;
110 pub struct EnumSetSameTypeHack<'a, T: EnumSetType + 'static> {
111 pub unified: &'a [T],
112 pub enum_set: EnumSet<T>,
115 /// An efficient set type for enums created with the [`enum_set_type!`](./macro.enum_set_type.html)
117 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
118 pub struct EnumSet<T : EnumSetType> {
119 #[doc(hidden)] pub __enumset_underlying: T::Repr
121 impl <T : EnumSetType> EnumSet<T> {
122 fn mask(bit: u8) -> T::Repr {
125 fn has_bit(&self, bit: u8) -> bool {
126 let mask = Self::mask(bit);
127 self.__enumset_underlying & mask == mask
130 /// Returns an empty set.
131 #[cfg(not(feature = "nightly"))]
132 pub fn new() -> Self {
133 EnumSet { __enumset_underlying: T::ZERO }
135 /// Returns an empty set.
136 #[cfg(feature = "nightly")]
137 pub const fn new() -> Self {
138 EnumSet { __enumset_underlying: T::ZERO }
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
147 /// Returns the raw bits of this set
148 pub fn to_bits(&self) -> u128 {
149 T::repr_to_u128(self.__enumset_underlying)
151 /// Constructs a bitset from raw bits
152 pub fn from_bits(bits: u128) -> Self {
153 EnumSet { __enumset_underlying: T::repr_from_u128(bits) }
156 /// Returns the number of values in this set.
157 pub fn len(&self) -> usize {
158 T::count_ones(self.__enumset_underlying)
160 /// Checks if the set is empty.
161 pub fn is_empty(&self) -> bool {
162 self.__enumset_underlying == T::ZERO
164 /// Removes all elements from the set.
165 pub fn clear(&mut self) {
166 self.__enumset_underlying = T::ZERO
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
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
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)
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 }
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 }
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 }
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 }
199 /// Checks whether this set contains a value.
200 pub fn contains(&self, value: T) -> bool {
201 self.has_bit(value.into_u8())
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());
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());
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
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
225 /// Creates an iterator over the values in this set.
226 pub fn iter(&self) -> EnumSetIter<T> {
227 EnumSetIter(*self, 0)
230 impl <T : EnumSetType> IntoIterator for EnumSet<T> {
232 type IntoIter = EnumSetIter<T>;
234 fn into_iter(self) -> Self::IntoIter {
238 impl <T : EnumSetType> Sub<EnumSet<T>> for EnumSet<T> {
240 fn sub(self, other: Self) -> Self::Output {
241 self.difference(other)
244 impl <T : EnumSetType> BitAnd<EnumSet<T>> for EnumSet<T> {
246 fn bitand(self, other: Self) -> Self::Output {
247 self.intersection(other)
250 impl <T : EnumSetType> BitOr<EnumSet<T>> for EnumSet<T> {
252 fn bitor(self, other: Self) -> Self::Output {
256 impl <T : EnumSetType> BitXor<EnumSet<T>> for EnumSet<T> {
258 fn bitxor(self, other: Self) -> Self::Output {
259 self.symmetrical_difference(other)
262 impl <T : EnumSetType> BitOr<T> for EnumSet<T> {
264 fn bitor(self, other: T) -> Self::Output {
265 EnumSet { __enumset_underlying: self.__enumset_underlying | Self::mask(other.into_u8()) }
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(" | ")?; }
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> {
289 fn next(&mut self) -> Option<Self::Item> {
290 while self.1 < T::VARIANT_COUNT {
293 if self.0.has_bit(bit) {
294 return Some(T::from_u8(bit))
299 fn size_hint(&self) -> (usize, Option<usize>) {
300 let left = T::count_ones((self.0).__enumset_underlying & !((T::ONE << self.1) - T::ONE));
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
327 compile_error!("enum_set_type! can only accept up to 128 variants.")
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
340 enum_set_type_internal! { @$next u128 $($args)* }
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
349 enum_set_type_internal! { @$next u64 $($args)* }
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
356 enum_set_type_internal! { @$next u32 $($args)* }
358 ($next:ident ($($args:tt)*)
359 $_00:ident $_01:ident $_02:ident $_03:ident $_04:ident $_05:ident $_06:ident $_07:ident
362 enum_set_type_internal! { @$next u16 $($args)* }
364 ($next:ident ($($args:tt)*) $($rest:ident)*) => {
365 enum_set_type_internal! { @$next u8 $($args)* }
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))*
379 (@body $repr:ident ($(#[$enum_attr:meta])*) ($($vis:tt)*) $enum_name:ident {
380 $($(#[$attr:meta])* $variant:ident,)*
382 $(#[$enum_attr])* #[repr(u8)]
383 #[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash, Debug)]
384 $($vis)* enum $enum_name {
385 $($(#[$attr])* $variant,)*
387 impl $crate::EnumSetType for $enum_name {
389 const ZERO: Self::Repr = 0;
390 const ONE : Self::Repr = 1;
391 const VARIANT_COUNT: u8 = enum_set_type_internal!(@count $($variant)*);
393 fn count_ones(val: Self::Repr) -> usize {
394 val.count_ones() as usize
396 fn into_u8(self) -> u8 {
399 fn from_u8(val: u8) -> Self {
400 unsafe { ::std::mem::transmute(val) }
403 fn repr_to_u128(bits: Self::Repr) -> u128 {
406 fn repr_from_u128(bits: u128) -> Self::Repr {
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)
419 /// Defines enums which can be used with EnumSet.
421 /// While attributes and documentation can be attached to the enums, the variants may not
427 /// # #[macro_use] extern crate enumset;
428 /// # use enumset::*;
431 /// A, B, C, D, E, F, G
434 /// /// Documentation
436 /// A, B, C, D, E, F, G,
437 /// #[doc(hidden)] __NonExhaustive,
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),* $(,)*
448 enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) (pub) $enum_name {
449 $($(#[$attr])* $variant,)*
451 enum_set_type!($($rest)*);
453 ($(#[$enum_attr:meta])* enum $enum_name:ident {
454 $($(#[$attr:meta])* $variant:ident),* $(,)*
456 enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) () $enum_name {
457 $($(#[$attr])* $variant,)*
459 enum_set_type!($($rest)*);
464 /// Defines enums which can be used with EnumSet.
466 /// While attributes and documentation can be attached to the enums, the variants may not
472 /// # #[macro_use] extern crate enumset;
473 /// # use enumset::*;
476 /// A, B, C, D, E, F, G
479 /// /// Documentation
481 /// A, B, C, D, E, F, G,
482 /// #[doc(hidden)] __NonExhaustive,
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),* $(,)*
494 enum_set_type_internal_count_variants!(body (($(#[$enum_attr])*) ($vis) $enum_name {
495 $($(#[$attr])* $variant,)*
497 enum_set_type!($($rest)*);
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.
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)`.
512 /// # #[macro_use] extern crate enumset;
513 /// # use enumset::*;
514 /// # enum_set_type! {
515 /// # enum Enum { A, B, C }
518 /// const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
519 /// assert_eq!(CONST_SET, Enum::A | Enum::B);
521 /// const EXPLICIT_CONST_SET: EnumSet<Enum> = enum_set!(Enum, Enum::A | Enum::B);
522 /// assert_eq!(EXPLICIT_CONST_SET, Enum::A | Enum::B);
526 /// This macro is strongly typed. For example, the following will not compile:
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 }
536 /// let type_error = enum_set!(Enum::A | Enum2::B);
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)))*
550 ($enum_name:ty, $($value:path)|* $(|)*) => {
551 $crate::EnumSet::<$enum_name> {
552 __enumset_underlying: 0 $(| (1 << ($value as $enum_name as u8)))*
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,
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,
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,
585 macro_rules! test_variants {
586 ($enum_name:ident $test_name:ident $($variant:ident,)*) => {
589 let count = enum_set_type_internal!(@count u8 $($variant)*);
591 assert!(($enum_name::$variant as u8) < count);
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,
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,
613 macro_rules! test_enum {
614 ($e:ident, $m:ident) => {
618 const CONST_SET: EnumSet<$e> = enum_set!($e, $e::A | $e::Y);
619 const EMPTY_SET: EnumSet<$e> = enum_set!($e, );
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());
629 fn basic_add_remove() {
630 let mut set = EnumSet::new();
634 assert_eq!(set, $e::A | $e::B | $e::C);
636 assert_eq!(set, $e::A | $e::C);
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());
645 assert!(set.is_empty());
649 fn basic_iter_test() {
650 let mut set = EnumSet::new();
656 let mut set_2 = EnumSet::new();
657 let vec: Vec<$e> = set.iter().collect();
661 assert_eq!(set, set_2);
663 let mut set_3 = EnumSet::new();
667 assert_eq!(set, set_3);
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);
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));
688 assert_eq!(format!("{:?}", $e::A | $e::B | $e::W), "EnumSet(A | B | W)");
694 test_enum!(Enum, small_enum);
695 test_enum!(LargeEnum, large_enum);