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 = (1 << 3) - 1;
27/// const FLAG_NAMES: &[&[&str]] = &[&["read"], &["write"], &["exec", "execute"]];
28/// const DEFAULT_NAME_MATCHER: NameMatcher = NameMatcher::Exact;
29/// }
30///
31/// type Permissions = BitFlags<u32, PermissionsTag>;
32///
33/// const READ: Permissions = Permissions::try_from_bit(0).unwrap();
34/// const WRITE: Permissions = Permissions::try_from_bit(1).unwrap();
35/// const EXEC: Permissions = Permissions::try_from_bit(2).unwrap();
36///
37/// assert_eq!(Permissions::try_from_bits(0b1), Some(READ));
38/// assert_eq!(Permissions::try_from_bits(0b11), Some(READ | WRITE));
39/// assert_eq!(Permissions::try_from_bits(0b111), Some(READ | WRITE | EXEC));
40/// assert_eq!(Permissions::try_from_bits(0b1111), None);
41/// ```
42///
43/// [`BitFlags`]: struct.BitFlags.html
44/// [`BitFlags<T, U>`]: struct.BitFlags.html
45/// [`BitFlags::try_from_bits`]: struct.BitFlags.html#method.try_from_bits
46/// [`BitFlags::from_bits_truncate`]: struct.BitFlags.html#method.from_bits_truncate
47/// [`BitFlags::truncate`]: struct.BitFlags.html#method.truncate
48/// [`BitFlags::complement`]: struct.BitFlags.html#method.complement
49/// [`BitFlags::from_bits_retain`]: struct.BitFlags.html#method.from_bits_retain
50pub trait BitFlagsSpec<T> {
51 /// A bit pattern whose set bits are the valid bits for this flag set.
52 ///
53 /// Bits not set in this value are invalid for the associated [`BitFlags`]
54 /// type.
55 /// They are rejected by [`BitFlags::try_from_bits`] and cleared by
56 /// [`BitFlags::from_bits_truncate`], [`BitFlags::truncate`],
57 /// [`BitFlags::complement`], and [`Not`](core::ops::Not).
58 ///
59 /// [`BitFlags`]: struct.BitFlags.html
60 /// [`BitFlags::try_from_bits`]: struct.BitFlags.html#method.try_from_bits
61 /// [`BitFlags::from_bits_truncate`]: struct.BitFlags.html#method.from_bits_truncate
62 /// [`BitFlags::truncate`]: struct.BitFlags.html#method.truncate
63 /// [`BitFlags::complement`]: struct.BitFlags.html#method.complement
64 const VALID_BITS_MASK: T;
65
66 /// A slice indexed by bit position, where each element contains the names
67 /// associated with that bit.
68 ///
69 /// The first name in each inner slice is used by [`BitFlag`]'s and
70 /// [`BitFlags`]'s [`Display`](core::fmt::Display) implementations.
71 /// All names are accepted when parsing.
72 /// An empty inner slice means the bit has no name.
73 ///
74 /// The index `i` corresponds to the bit mask `1 << i`.
75 ///
76 /// [`BitFlag`]: struct.BitFlag.html
77 /// [`BitFlags`]: struct.BitFlags.html
78 const FLAG_NAMES: &[&[&str]];
79
80 /// Controls whether the default [`FromStr`](core::str::FromStr) and
81 /// `Deserialize` implementations for [`BitFlags`] parse named flags
82 /// case-sensitively.
83 ///
84 /// If [`NameMatcher::Exact`], named flags are matched exactly.
85 /// If [`NameMatcher::AsciiCaseInsensitive`], named flags are matched
86 /// using ASCII case-insensitive comparison.
87 ///
88 /// This value does not affect methods that accept an explicit
89 /// [`NameMatcher`], such as [`BitFlags::try_from_str`].
90 ///
91 /// [`BitFlags`]: struct.BitFlags.html
92 /// [`BitFlags::try_from_str`]: struct.BitFlags.html#method.try_from_str
93 const DEFAULT_NAME_MATCHER: NameMatcher;
94}
95
96/// Controls how flag names are matched when parsing.
97///
98/// # Why `#[non_exhaustive]`
99///
100/// `NameMatcher` is only used as an input parameter to parsing APIs, never
101/// returned as a result.
102/// `#[non_exhaustive]` is appropriate here because new matcher variants can
103/// then be added in minor releases without breaking callers.
104#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
105#[non_exhaustive]
106pub enum NameMatcher {
107 /// Matches flag names exactly.
108 Exact,
109
110 /// Matches flag names using ASCII case-insensitive comparison.
111 AsciiCaseInsensitive,
112}
113
114impl NameMatcher {
115 /// Returns `true` if `given` matches `expected` according to this matcher.
116 #[inline]
117 #[must_use]
118 pub fn matches(self, given: &str, expected: &str) -> bool {
119 match self {
120 Self::Exact => given == expected,
121 Self::AsciiCaseInsensitive => given.eq_ignore_ascii_case(expected),
122 }
123 }
124}