Skip to main content

bitflags_lite/
flag_ext.rs

1use core::ops::{BitAnd, BitOr, BitXor, Not};
2
3use crate::{BitFlag, BitFlags, BitFlagsExt, BitFlagsSpec, util};
4
5/// Extension trait providing generic, non-const equivalents of the
6/// type-specific inherent methods on [`BitFlag`].
7///
8/// The inherent methods are implemented for each concrete integer type so they
9/// can be `const`.
10/// This trait exposes the same operations for generic `T`.
11pub trait BitFlagExt<T, U>: Sized
12where
13    U: ?Sized,
14{
15    /// Creates a bit flag from a [`BitFlags`] set.
16    ///
17    /// Returns `Some` if `flags` contains exactly one set bit and that bit is
18    /// valid according to [`BitFlagsSpec::VALID_BITS_MASK`].
19    ///
20    /// Returns `None` if `flags` is empty, has more than one bit set, or the
21    /// single set bit is not valid.
22    ///
23    /// This is equivalent to [`BitFlag::try_from_bits`] on `flags.bits()`.
24    #[must_use]
25    fn try_from_flags(flags: BitFlags<T, U>) -> Option<Self>
26    where
27        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
28        U: BitFlagsSpec<T>;
29
30    /// Creates a validated bit flag for bit index `i`.
31    ///
32    /// Returns `None` if `i` is not set in
33    /// [`BitFlagsSpec::VALID_BITS_MASK`].
34    ///
35    /// The index `i` must be less than the number of bits in the
36    /// storage type.
37    #[must_use]
38    fn try_from_bit(i: u8) -> Option<Self>
39    where
40        T: PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
41        U: BitFlagsSpec<T>;
42
43    /// Creates a validated bit flag from `bits` if exactly one bit is
44    /// set and that bit is valid according to
45    /// [`BitFlagsSpec::VALID_BITS_MASK`].
46    ///
47    /// Returns `None` if `bits` is zero, has more than one bit set, or
48    /// the single set bit is not valid.
49    #[must_use]
50    fn try_from_bits(bits: T) -> Option<Self>
51    where
52        T: PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
53        U: BitFlagsSpec<T>;
54
55    /// Creates a single-bit flag from `bits` if exactly one bit is set.
56    ///
57    /// The single set bit is not checked against
58    /// [`BitFlagsSpec::VALID_BITS_MASK`].
59    ///
60    /// Returns `None` if `bits` is `0` or has more than one bit set.
61    #[must_use]
62    fn try_from_bits_retain(bits: T) -> Option<Self>
63    where
64        T: util::IntOpsExt;
65
66    /// Returns `true` if this flag refers to a valid bit.
67    ///
68    /// A flag is valid when its bit index is within the width of `T` and the
69    /// corresponding bit is present in [`BitFlagsSpec::VALID_BITS_MASK`].
70    ///
71    /// [`BitFlag::from_bit_retain`] does not validate the bit index, so a
72    /// `BitFlag` constructed through it may be invalid.
73    #[must_use]
74    fn is_valid(&self) -> bool
75    where
76        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
77        U: BitFlagsSpec<T>;
78
79    /// Returns the single-bit mask for this flag, or `None` if the bit index is
80    /// outside the width of `T`.
81    ///
82    /// The mask is `1 << bit`. It is not checked against
83    /// [`BitFlagsSpec::VALID_BITS_MASK`]; use [`BitFlag::is_valid`] when tag
84    /// validity is required.
85    #[must_use]
86    fn mask(&self) -> Option<T>
87    where
88        T: util::IntOpsExt;
89
90    /// Returns the intersection of `self` and `other`.
91    ///
92    /// This is a raw-bit operation.
93    /// Invalid bits in either operand are preserved when they are set
94    /// in both operands.
95    #[must_use]
96    fn intersection(self, other: Self) -> BitFlags<T, U>
97    where
98        T: Copy + BitAnd<T, Output = T> + util::IntOpsExt;
99
100    /// Returns the union of `self` and `other`.
101    ///
102    /// This is a raw-bit operation.
103    /// Invalid bits in either operand are preserved.
104    #[must_use]
105    fn union(self, other: Self) -> BitFlags<T, U>
106    where
107        T: Copy + BitOr<T, Output = T> + util::IntOpsExt;
108
109    /// Returns the difference of `self` and `other`.
110    ///
111    /// The result contains bits that are set in `self` but not in
112    /// `other`.
113    /// This is a raw-bit operation.
114    /// Invalid bits already present in `self` are preserved unless they
115    /// are also set in `other`.
116    #[must_use]
117    fn difference(self, other: Self) -> BitFlags<T, U>
118    where
119        T: Copy + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt;
120
121    /// Returns the symmetric difference of `self` and `other`.
122    ///
123    /// The result contains bits that are set in exactly one of `self`
124    /// or `other`.
125    /// This is a raw-bit operation.
126    /// Invalid bits participate and may be preserved.
127    #[must_use]
128    fn symmetric_difference(self, other: Self) -> BitFlags<T, U>
129    where
130        T: Copy + BitXor<T, Output = T> + util::IntOpsExt;
131
132    /// Returns the complement of `self`.
133    ///
134    /// All valid bits not set in `self` become set, and all invalid
135    /// bits become unset.
136    /// The result always contains only valid bits.
137    #[must_use]
138    fn complement(self) -> BitFlags<T, U>
139    where
140        T: Copy + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
141        U: BitFlagsSpec<T>;
142}
143
144impl<T, U> BitFlagExt<T, U> for BitFlag<T, U>
145where
146    U: ?Sized,
147{
148    #[inline]
149    fn try_from_flags(flags: BitFlags<T, U>) -> Option<Self>
150    where
151        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
152        U: BitFlagsSpec<T>,
153    {
154        Self::try_from_bits(flags.bits())
155    }
156
157    #[inline]
158    fn try_from_bit(i: u8) -> Option<Self>
159    where
160        T: PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
161        U: BitFlagsSpec<T>,
162    {
163        let bits = T::ONE.checked_shl(u32::from(i))?;
164        ((i < T::BITS) && (bits & !U::VALID_BITS_MASK) == T::ZERO).then(|| Self::from_bit_retain(i))
165    }
166
167    #[inline]
168    fn try_from_bits(bits: T) -> Option<Self>
169    where
170        T: PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
171        U: BitFlagsSpec<T>,
172    {
173        if bits.count_ones() == 1
174            && let Some(bit) = bits.lowest_one()
175            && let Ok(bit) = u8::try_from(bit)
176        {
177            Self::try_from_bit(bit)
178        } else {
179            None
180        }
181    }
182
183    #[inline]
184    fn try_from_bits_retain(bits: T) -> Option<Self>
185    where
186        T: util::IntOpsExt,
187    {
188        if bits.count_ones() == 1
189            && let Some(bit) = bits.lowest_one()
190            && let Ok(bit) = u8::try_from(bit)
191        {
192            Some(Self::from_bit_retain(bit))
193        } else {
194            None
195        }
196    }
197
198    #[inline]
199    fn is_valid(&self) -> bool
200    where
201        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
202        U: BitFlagsSpec<T>,
203    {
204        (self.bit() < T::BITS) && BitFlags::<T, U>::from_flag(*self).is_valid()
205    }
206
207    #[inline]
208    fn mask(&self) -> Option<T>
209    where
210        T: util::IntOpsExt,
211    {
212        T::ONE.checked_shl(u32::from(self.bit()))
213    }
214
215    #[inline]
216    fn intersection(self, other: Self) -> BitFlags<T, U>
217    where
218        T: Copy + BitAnd<T, Output = T> + util::IntOpsExt,
219    {
220        <BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(self)
221            .intersection(<BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(other))
222    }
223
224    #[inline]
225    fn union(self, other: Self) -> BitFlags<T, U>
226    where
227        T: Copy + BitOr<T, Output = T> + util::IntOpsExt,
228    {
229        <BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(self)
230            .union(<BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(other))
231    }
232
233    #[inline]
234    fn difference(self, other: Self) -> BitFlags<T, U>
235    where
236        T: Copy + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
237    {
238        <BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(self)
239            .difference(<BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(other))
240    }
241
242    #[inline]
243    fn symmetric_difference(self, other: Self) -> BitFlags<T, U>
244    where
245        T: Copy + BitXor<T, Output = T> + util::IntOpsExt,
246    {
247        <BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(self)
248            .symmetric_difference(<BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(other))
249    }
250
251    #[inline]
252    fn complement(self) -> BitFlags<T, U>
253    where
254        T: Copy + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
255        U: BitFlagsSpec<T>,
256    {
257        <BitFlags<T, U> as BitFlagsExt<T, U>>::from_flag(self).complement()
258    }
259}