bitflags_lite/spec.rs
1/// Associates a bit-storage type `T` with the set of bits that are valid for a
2/// particular [`BitFlags`] tag.
3///
4/// Implement this trait for the tag type `U` in [`BitFlags<T, U>`].
5/// [`VALID_BITS_MASK`](Self::VALID_BITS_MASK) defines which bits are valid for
6/// the flag set.
7///
8/// Bits not set in `VALID_BITS_MASK` are invalid:
9/// - [`BitFlags::try_from_bits`] rejects them.
10/// - [`BitFlags::from_bits_truncate`] and [`BitFlags::truncate`] clear them.
11/// - [`BitFlags::complement`] and [`Not`](core::ops::Not) clear them.
12/// - [`BitFlags::from_bits_retain`] and operations that do not explicitly
13/// truncate may preserve them.
14///
15/// Unlike the `bitflags` crate, valid bits are not declared by a macro. They
16/// are part of this trait implementation for the tag type.
17///
18/// # Examples
19///
20/// ```
21/// use bitflags_lite::{BitFlags, BitFlagsSpec, NameMatcher};
22///
23/// struct PermissionsTag;
24///
25/// impl BitFlagsSpec<u32> for PermissionsTag {
26/// const VALID_BITS_MASK: u32 = 0b111;
27/// const FLAG_NAMES: &[&[&str]] = &[&["read"], &["write"], &["exec", "execute"]];
28/// const COMBINED_NAMES: &[(u32, &str)] = &[(0, "none"), (0b111, "rwx")];
29/// const DEFAULT_NAME_MATCHER: NameMatcher = NameMatcher::Exact;
30/// }
31///
32/// type Permissions = BitFlags<u32, PermissionsTag>;
33///
34/// const READ: Permissions = Permissions::try_from_bit(0).unwrap();
35/// const WRITE: Permissions = Permissions::try_from_bit(1).unwrap();
36/// const EXEC: Permissions = Permissions::try_from_bit(2).unwrap();
37///
38/// assert_eq!(Permissions::try_from_bits(0b1), Some(READ));
39/// assert_eq!(Permissions::try_from_bits(0b11), Some(READ | WRITE));
40/// assert_eq!(Permissions::try_from_bits(0b111), Some(READ | WRITE | EXEC));
41/// assert_eq!(Permissions::try_from_bits(0b1111), None);
42/// ```
43///
44/// [`BitFlags`]: struct.BitFlags.html
45/// [`BitFlags<T, U>`]: struct.BitFlags.html
46/// [`BitFlags::try_from_bits`]: struct.BitFlags.html#method.try_from_bits
47/// [`BitFlags::from_bits_truncate`]: struct.BitFlags.html#method.from_bits_truncate
48/// [`BitFlags::truncate`]: struct.BitFlags.html#method.truncate
49/// [`BitFlags::complement`]: struct.BitFlags.html#method.complement
50/// [`BitFlags::from_bits_retain`]: struct.BitFlags.html#method.from_bits_retain
51pub trait BitFlagsSpec<T>
52where
53 T: 'static,
54{
55 /// A bit pattern whose set bits are the valid bits for this flag set.
56 ///
57 /// Bits not set in this value are invalid for the associated [`BitFlags`]
58 /// type.
59 /// They are rejected by [`BitFlags::try_from_bits`] and cleared by
60 /// [`BitFlags::from_bits_truncate`], [`BitFlags::truncate`],
61 /// [`BitFlags::complement`], and [`Not`](core::ops::Not).
62 ///
63 /// [`BitFlags`]: struct.BitFlags.html
64 /// [`BitFlags::try_from_bits`]: struct.BitFlags.html#method.try_from_bits
65 /// [`BitFlags::from_bits_truncate`]: struct.BitFlags.html#method.from_bits_truncate
66 /// [`BitFlags::truncate`]: struct.BitFlags.html#method.truncate
67 /// [`BitFlags::complement`]: struct.BitFlags.html#method.complement
68 const VALID_BITS_MASK: T;
69
70 /// A slice indexed by bit position, where each element contains the names
71 /// associated with that bit.
72 ///
73 /// The first name in each inner slice is used by [`BitFlag`]'s and
74 /// [`BitFlags`]'s [`Display`](core::fmt::Display) implementations.
75 /// All names are accepted when parsing.
76 /// An empty inner slice means the bit has no name.
77 ///
78 /// The index `i` corresponds to the bit mask `1 << i`.
79 ///
80 /// [`BitFlag`]: struct.BitFlag.html
81 /// [`BitFlags`]: struct.BitFlags.html
82 const FLAG_NAMES: &[&[&str]];
83
84 /// Names for combinations of flags, consulted when parsing.
85 ///
86 /// Each entry pairs a bit pattern with the single name that should parse
87 /// to it. When parsing, the input string is matched against all entries;
88 /// the first match wins.
89 ///
90 /// The bit pattern may include bits that are not named in
91 /// [`FLAG_NAMES`], or that are not declared as individual flags at all.
92 /// This const does not validate against
93 /// [`VALID_BITS_MASK`](Self::VALID_BITS_MASK).
94 /// Parsing preserves whatever bits the entry contains.
95 ///
96 /// This const is **not** consulted by [`Display`](core::fmt::Display).
97 /// Formatting a value with multiple bits set always writes the individual
98 /// flag names from [`FLAG_NAMES`], never a combined name.
99 ///
100 /// [`FLAG_NAMES`]: trait.BitFlagsSpec.html#associatedconstant.FLAG_NAMES
101 const COMBINED_NAMES: &[(T, &str)];
102
103 /// Controls whether the default [`FromStr`](core::str::FromStr) and
104 /// `Deserialize` implementations for [`BitFlags`] parse named flags
105 /// case-sensitively.
106 ///
107 /// If [`NameMatcher::Exact`], named flags are matched exactly.
108 /// If [`NameMatcher::AsciiCaseInsensitive`], named flags are matched
109 /// using ASCII case-insensitive comparison.
110 ///
111 /// This value does not affect methods that accept an explicit
112 /// [`NameMatcher`], such as [`BitFlags::try_from_str`].
113 ///
114 /// [`BitFlags`]: struct.BitFlags.html
115 /// [`BitFlags::try_from_str`]: struct.BitFlags.html#method.try_from_str
116 const DEFAULT_NAME_MATCHER: NameMatcher;
117}
118
119/// Controls how flag names are matched when parsing.
120///
121/// # Why `#[non_exhaustive]`
122///
123/// `NameMatcher` is only used as an input parameter to parsing APIs, never
124/// returned as a result.
125/// `#[non_exhaustive]` is appropriate here because new matcher variants can
126/// then be added in minor releases without breaking callers.
127#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
128#[non_exhaustive]
129pub enum NameMatcher {
130 /// Matches flag names exactly.
131 Exact,
132
133 /// Matches flag names using ASCII case-insensitive comparison.
134 AsciiCaseInsensitive,
135}
136
137impl NameMatcher {
138 /// Returns `true` if `given` matches `expected` according to this matcher.
139 #[inline]
140 #[must_use]
141 pub fn matches(self, given: &str, expected: &str) -> bool {
142 match self {
143 Self::Exact => given == expected,
144 Self::AsciiCaseInsensitive => given.eq_ignore_ascii_case(expected),
145 }
146 }
147}