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