Skip to main content

bitflags_lite/
lib.rs

1//! The `bitflags-lite` crate provides a lightweight, generic bitflags
2//! implementation for Rust.
3//!
4//! [`BitFlags<T, U>`] is a `#[repr(transparent)]` wrapper around an integer `T`
5//! that adds a compile-time tag type `U`.
6//! The tag distinguishes flag sets that share the same storage type and
7//! describes which bits are valid through the [`BitFlagsSpec`] trait.
8//!
9//! Flag sets can be defined either through the [`bitflags!`] macro, which
10//! generates the trait implementation and named constants from a compact
11//! declaration, or by implementing [`BitFlagsSpec`] directly.
12//! Both forms produce the same types and the same runtime behavior.
13//!
14//! The crate is `no_std` and `no_alloc` compatible, and const-friendly.
15//!
16//!
17//! # When to choose `bitflags`, `bitflags-lite`, or `enumflags2`
18//!
19//! - Choose [`bitflags`] if you want the mature and battle-tested crate, and
20//!   the ecosystem-standard macro, and the ability to extend each flag set with
21//!   inherent methods or third-party trait implementations.
22//! - Choose [`bitflags-lite`] if you want a reusable generic [`BitFlags<T, U>`]
23//!   with a small, inspectable expansion, optionally generated by a concise
24//!   macro, and you don't need the ability to extend each flag set with
25//!   inherent methods or third-party trait implementations.
26//! - Choose [`enumflags2`] if you want a single-flag type distinct from the set
27//!   type, enum-variant-driven definitions, and match/iter over variants.
28//!
29//!
30//! # About
31//!
32//! Macro-based [`bitflags`] crate generate a distinct struct for every flag
33//! set.
34//! Each invocation re-expands the full method set, and the resulting types
35//! share no common trait or type with one another.
36//! By contrast, `bitflags-lite` defines [`BitFlags<T, U>`] once and asks you to
37//! specialize it through a plain trait implementation.
38//! The provided [`bitflags!`] macro is a convenience wrapper that generates
39//! that trait impl and the named constants — it does not generate a new type.
40//!
41//! Design Highlights:
42//! - **Single-flag vs. set distinction.** [`BitFlag<T, U>`] represents one bit
43//!   index. [`BitFlags<T, U>`] represents a set. They convert into each other
44//!   and interoperate through the usual operators.
45//! - **Invalid bits are representable.** A [`BitFlags`] value may contain bits
46//!   not set in [`BitFlagsSpec::VALID_BITS_MASK`]; they are preserved by
47//!   raw-bit operations and cleared by [`BitFlags::truncate`],
48//!   [`BitFlags::complement`], and [`Not`](core::ops::Not). Use
49//!   [`BitFlags::is_valid`] to check.
50//! - **Const-friendly.** Every constructor, accessor, and combinator on the
51//!   concrete integer types is a `const fn`. The generic equivalents live in
52//!   the [`BitFlagsExt`] and [`BitFlagExt`] extension traits.
53//! - **No allocation.** Parsing and formatting work without `alloc`. The
54//!   `alloc` feature only enriches error messages with the offending input.
55//! - **No hidden type generation.** Even with the [`bitflags!`] macro, no new
56//!   type is created per flag set. The macro builds on the same generic
57//!   [`BitFlags<T, U>`], so all flag sets remain one type family.
58//!
59//!
60//! # Usage
61//!
62//! ```toml
63//! [dependencies]
64//! bitflags-lite = "0.3.0"
65//! ```
66//!
67//! With optional features:
68//!
69//! ```toml
70//! [dependencies]
71//! bitflags-lite = { version = "0.3.0", features = [ "serde", "bytemuck" ] }
72//! ```
73//!
74//!
75//! # Examples
76//!
77//! ## With the [`bitflags!`] macro
78//!
79//! The macro generates the tag type, the flag-set alias, the [`BitFlagsSpec`]
80//! implementation, and the named constants from one compact declaration:
81//!
82//! ```rust
83//! use core::str::FromStr;
84//!
85//! use bitflags_lite::{BitFlag, BitFlags, BitFlagsSpec, NameMatcher};
86//!
87//! bitflags_lite::bitflags! {
88//!     #![storage(u32)]
89//!
90//!     pub struct PermissionsTag;
91//!
92//!     pub bit READ  = 0, &["read"];
93//!     pub bit WRITE = 1, &["write"];
94//!     pub bit EXEC  = 2, &["exec", "execute"];
95//!
96//!     pub mask RWX  = [READ, WRITE, EXEC], "rwx";
97//!     pub mask NONE = 0, "none";
98//! }
99//!
100//! pub type Permission = BitFlag<u32, PermissionsTag>;
101//! pub type Permissions = BitFlags<u32, PermissionsTag>;
102//!
103//! let rwx = READ | WRITE | EXEC;
104//! assert!(rwx.contains(READ.into()));
105//! assert!(rwx.contains(WRITE.into()));
106//! assert!(rwx.contains(EXEC.into()));
107//! assert!(rwx.contains(RWX));
108//!
109//! let read_exec = READ | EXEC;
110//! assert!(!read_exec.contains(WRITE.into()));
111//!
112//! // Combined names participate in parsing.
113//! let parsed = Permissions::from_str("rwx").unwrap();
114//! assert_eq!(format!("{parsed}"), "read | write | exec");
115//!
116//! let parsed = Permissions::from_str("read | 0x18 | execute").unwrap();
117//! assert_eq!(format!("{parsed}"), "read | exec | 0x18");
118//!
119//! // Iteration yields individual BitFlag values.
120//! let flags: Vec<Permission> = parsed.into_iter().collect();
121//! assert_eq!(
122//!     flags,
123//!     [
124//!         READ,
125//!         EXEC,
126//!         BitFlag::from_bit_retain(3),
127//!         BitFlag::from_bit_retain(4),
128//!     ]
129//! );
130//!
131//! let formatted: Vec<String> = flags.iter().map(ToString::to_string).collect();
132//! assert_eq!(formatted, ["read", "exec", "0x8", "0x10"]);
133//!
134//! let named_only: Vec<&'static str> = flags.iter().filter_map(BitFlag::name).collect();
135//! assert_eq!(named_only, ["read", "exec"]);
136//! ```
137//!
138//! ## Without the macro
139//!
140//! The same flag set can be written manually.
141//! This is what the macro expands to, and it is fully supported as a public
142//! API:
143//!
144//! ```rust
145//! use core::str::FromStr;
146//!
147//! use bitflags_lite::{BitFlag, BitFlags, BitFlagsSpec, NameMatcher};
148//!
149//! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Default, Debug)]
150//! struct PermissionsTag;
151//!
152//! impl BitFlagsSpec<u32> for PermissionsTag {
153//!     const VALID_BITS_MASK: u32 = 0b111;
154//!     const FLAG_NAMES: &[&[&str]] = &[&["read"], &["write"], &["exec", "execute"]];
155//!     const COMBINED_NAMES: &[(u32, &str)] = &[(0, "none"), (0b111, "rwx")];
156//!     const DEFAULT_NAME_MATCHER: NameMatcher = NameMatcher::Exact;
157//! }
158//!
159//! type Permission = BitFlag<u32, PermissionsTag>;
160//! type Permissions = BitFlags<u32, PermissionsTag>;
161//!
162//! // Constructors are `const` for concrete integer types.
163//! const READ: Permission = Permission::try_from_bit(0).unwrap();
164//! const WRITE: Permission = Permission::try_from_bit(1).unwrap();
165//! const EXEC: Permission = Permission::try_from_bit(2).unwrap();
166//! const RWX: Permissions = Permissions::try_from_bits(0b111).unwrap();
167//! ```
168//!
169//! Constants can also be defined through an inherent implementation, a trait,
170//! or an associated `const` on the tag type.
171//!
172//! ## Type-safety across flag sets
173//!
174//! The tag type keeps flag sets distinct even when they share a storage type.
175//! The following example deliberately fails to compile:
176//!
177//! ```rust,compile_fail
178//! use bitflags_lite::{BitFlags, BitFlagsSpec, NameMatcher};
179//!
180//! struct PermsTag;
181//! type Perms = BitFlags<u8, PermsTag>;
182//! impl BitFlagsSpec<u8> for PermsTag {
183//!     const VALID_BITS_MASK: u8 = (1 << 3) - 1;
184//!     const FLAG_NAMES: &[&[&str]] = &[&["read"], &["write"], &["exec", "execute"]];
185//!     const COMBINED_NAMES: &[(u8, &str)] = &[(0, "none"), (0b111, "rwx")];
186//!     const DEFAULT_NAME_MATCHER: NameMatcher = NameMatcher::AsciiCaseInsensitive;
187//! }
188//!
189//! struct KeyboardModifiersTag;
190//! type KeyboardModifiers = BitFlags<u8, KeyboardModifiersTag>;
191//! impl BitFlagsSpec<u8> for KeyboardModifiersTag {
192//!     const VALID_BITS_MASK: u8 = (1 << 4) - 1;
193//!     const FLAG_NAMES: &[&[&str]] = &[&["Shift"], &["Ctrl"], &["Alt"], &["Meta"]];
194//!     const COMBINED_NAMES: &[(u8, &str)] = &[];
195//!     const DEFAULT_NAME_MATCHER: NameMatcher = NameMatcher::AsciiCaseInsensitive;
196//! }
197//!
198//! let rwx: Perms = Perms::try_from_bits(0b111).unwrap();
199//! let keyboard_modifiers: KeyboardModifiers = rwx;
200//! //                                          ^^^
201//! // ❌ error[E0308]: mismatched types
202//! // expected struct `BitFlags<_, KeyboardModifiersTag>`
203//! //    found struct `BitFlags<_, test::PermsTag>`
204//! ```
205//!
206//!
207//! # Comparison with Existing Crates
208//!
209//! ## Definition
210//!
211//! | Feature | `bitflags-lite` | `bitflags` v2 | `enumflags2` v0.7 |
212//! |:--:|:--:|:--:|:--:|
213//! | Defined by trait impl | ✅ `BitFlagsSpec<T>` | ⛔️ No | ⛔️ No |
214//! | Defined by macro | ✅ `bitflags!` | ✅ `bitflags!` | ⛔️ No |
215//! | Defined by attribute | ⛔️ No | ⛔️ No | ✅ `#[bitflags(...)]` |
216//! | Generates a distinct new type | ⛔️ No (generic over `U`) | ✅ Yes | ⛔️ No (uses user enum) |
217//!
218//! ## Type model
219//!
220//! | Feature | `bitflags-lite` | `bitflags` v2 | `enumflags2` v0.7 |
221//! |:--:|:--:|:--:|:--:|
222//! | Single-flag vs. set distinction | ✅ `BitFlag` / `BitFlags` | ⛔️ No | ✅ `T` / `BitFlags` |
223//! | Iteration yields | `BitFlag<T, U>` | `Flags` (self, one bit) | `enum T` (variant) |
224//! | Match exhaustively on single flag | ⛔️ No | ⛔️ No | ✅ `match flag { T::A => ... }` |
225//! | Generic over a single flag | ✅ `BitFlag<T, U>` | ⛔️ No | ✅ `enum T` |
226//! | Generic over flag sets | ✅ `BitFlags<T, U>` | ⛔️ No | ✅ `BitFlags<T, N>` |
227//!
228//! ## Extension
229//!
230//! | Feature | `bitflags-lite` | `bitflags` v2 | `enumflags2` v0.7 |
231//! |:--:|:--:|:--:|:--:|
232//! | Inherent methods | ⛔️ No | ✅ Yes | ⛔️ No |
233//! | Third-party trait impls | ⛔️ No | ✅ Yes | ⛔️ No |
234//! | Local trait impls | ✅ Yes | ✅ Yes | ✅ Yes |
235//!
236//! ## Capabilities
237//!
238//! | Feature | `bitflags-lite` | `bitflags` v2 | `enumflags2` v0.7 |
239//! |:--:|:--:|:--:|:--:|
240//! | Most methods const | ✅ Integer impls | ✅ Targeted codegen | ⚠️ Limited |
241//! | Multi-bit flags | ⚠️ Parse-only | ✅ Format and parse | ⛔️ No |
242//! | Custom display name | ✅ Yes | ✅ `#[name]` | ⛔️ No |
243//! | Alias names for parsing | ✅ Yes | ⛔️ No | ⛔️ No |
244//! | Format with names | ✅ Yes | ✅ Yes | ✅ Yes |
245//! | Parse from names | ✅ Yes | ✅ Yes | ⛔️ No |
246//! | Case-insensitive parsing | ✅ Configurable | ⛔️ No | ⛔️ No |
247//! | Custom default value | ⛔️ No | ✅ `#[default]` | ✅ `#[default]` |
248//! | Only valid bits representable | ⛔️ No | ⛔️ No | ✅ Yes |
249//! | Invalid bits representable | ✅ Yes | ✅ Yes | ⛔️ No |
250//!
251//! <!---
252//!   Invalid bits are really not allowed in `enumflags2`.
253//!   Its `from_bits_unchecked` unsafe method requires that
254//!   "All bits set in val must correspond to a value of the enum".
255//! -->
256//!
257//!
258//! # Documentation
259//!
260//! [API Documentation]
261//!
262//!
263//! # Feature flags
264//!
265//!
266//! - `alloc` (implied by `std`, enabled by default): enriches parse errors with
267//!   the offending input.
268//! - `std` (enabled by default): enables the `alloc` feature.
269//! - `arbitrary`: implements `Arbitrary` for `BitFlag<T, U>` and `BitFlags<T,
270//!   U>`.
271//! - `serde`: implements `serde::Serialize` and `serde::Deserialize` for
272//!   `BitFlag<T, U>` and `BitFlags<T, U>`, round-tripping through flag strings.
273//! - `bytemuck`: implements `Zeroable` and `Pod` for `BitFlag<T, U>` and
274//!   `BitFlags<T, U>`, allowing them to be used in plain-old-data contexts.
275//!
276//!
277//! # License
278//!
279//! Licensed under either of
280//!
281//! - Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or <https://www.apache.org/licenses/LICENSE-2.0>)
282//! - MIT license ([LICENSE-MIT](LICENSE-MIT) or <https://opensource.org/licenses/MIT>)
283//!
284//! at your option.
285//!
286//!
287//! # Contribution
288//!
289//! Unless you explicitly state otherwise, any contribution intentionally
290//! submitted for inclusion in the work by you, as defined in the Apache-2.0
291//! license, shall be dual licensed as above, without any
292//! additional terms or conditions.
293//!
294//! [API Documentation]: https://docs.rs/bitflags-lite/latest/bitflags-lite/
295//! [`bitflags`]: https://crates.io/crates/bitflags
296//! [`enumflags2`]: https://crates.io/crates/enumflags2
297//! [`bitflags-lite`]: https://crates.io/crates/bitflags-lite
298//! [`bitflags!`]: macro.bitflags.html
299//! [`BitFlag<T, U>`]: struct.BitFlag.html
300//! [`BitFlags<T, U>`]: struct.BitFlags.html
301//! [`BitFlags`]: struct.BitFlags.html
302//! [`BitFlagExt`]: trait.BitFlagExt.html
303//! [`BitFlagsExt`]: trait.BitFlagsExt.html
304//! [`BitFlagsSpec`]: trait.BitFlagsSpec.html
305//! [`BitFlagsSpec::VALID_BITS_MASK`]: trait.BitFlagsSpec.html#associatedconstant.VALID_BITS_MASK
306//! [`BitFlags::truncate`]: struct.BitFlags.html#method.truncate
307//! [`BitFlags::complement`]: struct.BitFlags.html#method.complement
308//! [`BitFlags::is_valid`]: struct.BitFlags.html#method.is_valid
309
310#![no_std]
311#![cfg_attr(docsrs, feature(doc_cfg))]
312
313#[cfg(feature = "alloc")]
314extern crate alloc;
315
316#[cfg(feature = "std")]
317extern crate std;
318
319mod flag;
320mod flag_ext;
321mod flags;
322mod flags_ext;
323mod iter;
324mod macros;
325mod spec;
326pub mod util;
327
328pub use flag::*;
329pub use flag_ext::*;
330pub use flags::*;
331pub use flags_ext::*;
332pub use iter::*;
333pub use spec::*;
334
335#[cfg(all(test, not(doc)))]
336mod integration_tests_deps {
337    use serde_test as _;
338    use version_sync as _;
339}