1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
#![no_std]
#![deny(missing_docs)]
#![allow(clippy::missing_safety_doc)] // The safety requirement is "use the procedural derive".
#![allow(clippy::needless_range_loop)] // range loop style is clearer in most places in enumset
#![cfg_attr(docsrs, feature(doc_cfg))]
//! A library for defining enums that can be used in compact bit sets. It supports arbitrarily
//! large enums, and has very basic support for using them in constants.
//!
//! The following feature flags may be used for this crate:
//!
//! * `serde` enables serialization support for [`EnumSet`].
//! * `alloc` enables functions that require allocation.
//!
//! # Defining enums for use with EnumSet
//!
//! Enums to be used with [`EnumSet`] should be defined using `#[derive(EnumSetType)]`:
//!
//! ```rust
//! # use enumset::*;
//! #[derive(EnumSetType, Debug)]
//! pub enum Enum {
//! A, B, C, D, E, F, G,
//! }
//! ```
//!
//! For more information on more advanced use cases, see the documentation for
//! [`#[derive(EnumSetType)]`](./derive.EnumSetType.html).
//!
//! # Working with EnumSets
//!
//! EnumSets can be constructed via [`EnumSet::new()`] like a normal set. In addition,
//! `#[derive(EnumSetType)]` creates operator overloads that allow you to create EnumSets like so:
//!
//! ```rust
//! # use enumset::*;
//! # #[derive(EnumSetType, Debug)] pub enum Enum { A, B, C, D, E, F, G }
//! let new_set = Enum::A | Enum::C | Enum::G;
//! assert_eq!(new_set.len(), 3);
//! ```
//!
//! All bitwise operations you would expect to work on bitsets also work on both EnumSets and
//! enums with `#[derive(EnumSetType)]`:
//! ```rust
//! # use enumset::*;
//! # #[derive(EnumSetType, Debug)] pub enum Enum { A, B, C, D, E, F, G }
//! // Intersection of sets
//! assert_eq!((Enum::A | Enum::B) & Enum::C, EnumSet::empty());
//! assert_eq!((Enum::A | Enum::B) & Enum::A, Enum::A);
//! assert_eq!(Enum::A & Enum::B, EnumSet::empty());
//!
//! // Symmetric difference of sets
//! assert_eq!((Enum::A | Enum::B) ^ (Enum::B | Enum::C), Enum::A | Enum::C);
//! assert_eq!(Enum::A ^ Enum::C, Enum::A | Enum::C);
//!
//! // Difference of sets
//! assert_eq!((Enum::A | Enum::B | Enum::C) - Enum::B, Enum::A | Enum::C);
//!
//! // Complement of sets
//! assert_eq!(!(Enum::E | Enum::G), Enum::A | Enum::B | Enum::C | Enum::D | Enum::F);
//! ```
//!
//! The [`enum_set!`] macro allows you to create EnumSets in constant contexts:
//!
//! ```rust
//! # use enumset::*;
//! # #[derive(EnumSetType, Debug)] pub enum Enum { A, B, C, D, E, F, G }
//! const CONST_SET: EnumSet<Enum> = enum_set!(Enum::A | Enum::B);
//! assert_eq!(CONST_SET, Enum::A | Enum::B);
//! ```
//!
//! Mutable operations on the [`EnumSet`] otherwise similarly to Rust's builtin sets:
//!
//! ```rust
//! # use enumset::*;
//! # #[derive(EnumSetType, Debug)] pub enum Enum { A, B, C, D, E, F, G }
//! let mut set = EnumSet::new();
//! set.insert(Enum::A);
//! set.insert_all(Enum::E | Enum::G);
//! assert!(set.contains(Enum::A));
//! assert!(!set.contains(Enum::B));
//! assert_eq!(set, Enum::A | Enum::E | Enum::G);
//! ```
#[cfg(feature = "alloc")]
extern crate alloc;
mod macros;
mod repr;
mod set;
mod traits;
pub use crate::macros::__internal;
pub use crate::set::{EnumSet, EnumSetIter};
pub use crate::traits::{EnumSetType, EnumSetTypeWithRepr};
/// The procedural macro used to derive [`EnumSetType`], and allow enums to be used with
/// [`EnumSet`].
///
/// # Limitations
///
/// Currently, the following limitations apply to what kinds of enums this macro may be used with:
///
/// * The enum must have no data fields in any variant.
/// * Variant discriminators must be zero or positive.
/// * No variant discriminator may be larger than `0xFFFFFFBF`. This is chosen to limit problems
/// involving overflow and similar edge cases.
/// * Variant discriminators must be defined with integer literals. Expressions like `V = 1 + 1`
/// are not currently supported.
///
/// # Additional Impls
///
/// In addition to the implementation of `EnumSetType`, this procedural macro creates multiple
/// other impls that are either required for the macro to work, or make the procedural macro more
/// ergonomic to use.
///
/// A full list of traits implemented as is follows:
///
/// * [`Copy`], [`Clone`], [`Eq`], [`PartialEq`] implementations are created to allow `EnumSet`
/// to function properly. These automatic implementations may be suppressed using
/// `#[enumset(no_super_impls)]`, but these traits must still be implemented in another way.
/// * [`PartialEq`], [`Sub`], [`BitAnd`], [`BitOr`], [`BitXor`], and [`Not`] implementations are
/// created to allow the crate to be used more ergonomically in expressions. These automatic
/// implementations may be suppressed using `#[enumset(no_ops)]`.
///
/// # Options
///
/// Options are given with `#[enumset(foo)]` annotations attached to the same enum as the derive.
/// Multiple options may be given in the same annotation using the `#[enumset(foo, bar)]` syntax.
///
/// A full list of options is as follows:
///
/// * `#[enumset(no_super_impls)]` prevents the derive from creating implementations required for
/// [`EnumSet`] to function. When this attribute is specified, implementations of [`Copy`],
/// [`Clone`], [`Eq`], and [`PartialEq`]. This can be useful if you are using a code generator
/// that already derives these traits. These impls should function identically to the
/// automatically derived versions, or unintentional behavior may be a result.
/// * `#[enumset(no_ops)` prevents the derive from implementing any operator traits.
/// * `#[enumset(crate_name = "enumset2")]` may be used to change the name of the `enumset` crate
/// used in the generated code. When the `std` feature is enabled, enumset parses `Cargo.toml`
/// to determine the name of the crate, and this flag is unnecessary.
/// * `#[enumset(repr = "u8")]` may be used to specify the in-memory representation of `EnumSet`s
/// of this enum type. The effects of this are described in [the `EnumSet` documentation under
/// “FFI, Safety and `repr`”][EnumSet#ffi-safety-and-repr]. Allowed types are `u8`, `u16`, `u32`,
/// `u64` and `u128`. If this is not used, then the derive macro will choose a type to best fit
/// the enum, but there are no guarantees about which type will be chosen.
/// * `#[enumset(repr = "array")]` forces the `EnumSet` of this type to be backed with an array,
/// even if all the variants could fit into a primitive numeric type.
///
/// When the `serde` feature is used, the following features may also be specified. These options
/// may be used (with no effect) when building without the feature enabled:
///
/// * `#[enumset(serialize_repr = "…")]` may be used to override the way the `EnumSet` is
/// serialized. Valid options are `u8`, `u16`, `u32`, `u64`, `list`, `map` and `array`. For more
/// information, see the ["Serialization" section of the `EnumSet` documentation]
/// (EnumSet#serialization).
/// * `#[enumset(serialize_deny_unknown)]` causes the generated deserializer to return an error
/// for unknown bits instead of silently ignoring them.
///
/// # Examples
///
/// Deriving a plain EnumSetType:
///
/// ```rust
/// # use enumset::*;
/// #[derive(EnumSetType)]
/// pub enum Enum {
/// A, B, C, D, E, F, G,
/// }
/// ```
///
/// Deriving a sparse EnumSetType:
///
/// ```rust
/// # use enumset::*;
/// #[derive(EnumSetType)]
/// pub enum SparseEnum {
/// A = 10, B = 20, C = 30, D = 127,
/// }
/// ```
///
/// Deriving an EnumSetType without adding ops:
///
/// ```rust
/// # use enumset::*;
/// #[derive(EnumSetType)]
/// #[enumset(no_ops)]
/// pub enum NoOpsEnum {
/// A, B, C, D, E, F, G,
/// }
/// ```
///
/// [`Sub`]: core::ops::Sub
/// [`BitAnd`]: core::ops::BitAnd
/// [`BitOr`]: core::ops::BitOr
/// [`BitXor`]: core::ops::BitXor
/// [`Not`]: core::ops::Not
pub use enumset_derive::EnumSetType;