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