Skip to main content

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}