Skip to main content

bitflags_lite/
flags_ext.rs

1use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
2
3use crate::{BitFlag, BitFlags, BitFlagsSpec, util};
4
5/// Extension trait providing generic, non-const equivalents of the
6/// type-specific inherent methods on [`BitFlags`].
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 BitFlagsExt<T, U>: Sized
12where
13    U: ?Sized,
14{
15    /// Creates a flag set from a single [`BitFlag`].
16    ///
17    /// The bit index is not validated against
18    /// [`BitFlagsSpec::VALID_BITS_MASK`].
19    /// The resulting value may contain an invalid bit.
20    ///
21    /// If the flag's index is outside the width of `T`, the result is
22    /// [`BitFlags::empty`].
23    #[must_use]
24    fn from_flag(bit_flag: BitFlag<T, U>) -> Self
25    where
26        T: util::IntOpsExt;
27
28    /// Creates a flag set with only the bit at index `bit` set.
29    ///
30    /// The bit index is not validated against
31    /// [`BitFlagsSpec::VALID_BITS_MASK`].
32    /// The resulting value may contain an invalid bit. Use
33    /// [`BitFlags::try_from_bit`] or [`BitFlags::from_bits_truncate`] when
34    /// validation or truncation is required.
35    ///
36    /// If `bit` is outside the width of `T`, the result is
37    /// [`BitFlags::empty`].
38    #[must_use]
39    fn from_bit_retain(bit: u8) -> Self
40    where
41        T: util::IntOpsExt;
42
43    /// Creates a flag set with only the bit at index `bit` set, clearing the
44    /// bit if it is not valid for the tag.
45    ///
46    /// This is the bit-index counterpart to [`BitFlags::from_bits_truncate`].
47    /// If `bit` is outside the width of `T`, or if the corresponding bit is
48    /// not present in [`BitFlagsSpec::VALID_BITS_MASK`], the result is
49    /// [`BitFlags::empty`].
50    ///
51    /// The result always contains either exactly one bit or no bits.
52    ///
53    /// Use [`BitFlags::try_from_bit`] when the caller needs to distinguish a
54    /// valid index from an invalid one.
55    #[must_use]
56    fn from_bit_truncate(bit: u8) -> Self
57    where
58        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
59        U: BitFlagsSpec<T>;
60
61    /// Creates a flag set from bit index `bit` if that bit is valid.
62    ///
63    /// Returns `None` if `bit` is outside the width of `T` or if the resulting
64    /// bit is not present in [`BitFlagsSpec::VALID_BITS_MASK`].
65    #[must_use]
66    fn try_from_bit(bit: u8) -> Option<Self>
67    where
68        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
69        U: BitFlagsSpec<T>;
70
71    /// Creates a flag set from raw bits if all set bits are valid.
72    ///
73    /// Returns `None` if `bits` contains any bit not present in
74    /// [`BitFlagsSpec::VALID_BITS_MASK`].
75    ///
76    /// Use [`BitFlags::from_bits_retain`] to keep invalid bits, or
77    /// [`BitFlags::from_bits_truncate`] to clear them.
78    #[doc(alias = "from_bits")]
79    #[must_use]
80    fn try_from_bits(bits: T) -> Option<Self>
81    where
82        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
83        U: BitFlagsSpec<T>;
84
85    /// Creates a flag set from raw bits, clearing any bits not present in
86    /// [`BitFlagsSpec::VALID_BITS_MASK`].
87    ///
88    /// This always succeeds and never stores invalid bits.
89    #[must_use]
90    fn from_bits_truncate(bits: T) -> Self
91    where
92        T: BitAnd<T, Output = T>,
93        U: BitFlagsSpec<T>;
94
95    /// Returns `true` if no bits are set.
96    ///
97    /// This checks the raw stored bits.
98    /// A value containing only invalid bits is not empty.
99    #[must_use]
100    fn is_empty(&self) -> bool
101    where
102        T: Copy + PartialEq + util::IntOpsExt;
103
104    /// Returns `true` if all set bits in `self` are valid for this tag.
105    ///
106    /// A `BitFlags` value can contain bits not present in
107    /// [`BitFlagsSpec::VALID_BITS_MASK`] after construction with
108    /// [`BitFlags::from_bits_retain`] or after raw-bit operations such as
109    /// [`BitFlags::insert`], [`BitFlags::toggle`], and [`BitFlags::union`].
110    /// This method returns `false` for such values.
111    ///
112    /// Use [`BitFlags::truncate`] or [`BitFlags::from_bits_truncate`] to
113    /// restrict a value to its valid bits.
114    #[doc(alias = "is_all")]
115    #[must_use]
116    fn is_valid(&self) -> bool
117    where
118        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
119        U: BitFlagsSpec<T>;
120
121    /// Returns `true` if `self` and `other` have at least one set bit in
122    /// common.
123    ///
124    /// This compares raw bits.
125    /// Invalid bits participate in the comparison if they are present.
126    #[must_use]
127    fn intersects(&self, other: Self) -> bool
128    where
129        T: Copy + PartialEq + BitAnd<T, Output = T> + util::IntOpsExt;
130
131    /// Returns `true` if all bits set in `other` are also set in `self`.
132    ///
133    /// This compares raw bits.
134    /// Invalid bits participate in the comparison if they are present.
135    #[must_use]
136    fn contains(&self, other: Self) -> bool
137    where
138        T: Copy + PartialEq + BitAnd<T, Output = T>;
139
140    /// Removes all bits from `self`, including any invalid bits.
141    ///
142    /// This is equivalent to assigning [`BitFlags::empty`] to `self`.
143    fn clear(&mut self)
144    where
145        T: util::IntOpsExt;
146
147    /// Clears all bits not present in [`BitFlagsSpec::VALID_BITS_MASK`].
148    ///
149    /// This leaves `self` unchanged if it already contains only valid bits.
150    fn truncate(&mut self)
151    where
152        T: BitAndAssign<T>,
153        U: BitFlagsSpec<T>;
154
155    /// Inserts all bits from `other`.
156    ///
157    /// This is a raw-bit operation.
158    /// It does not validate or clear invalid bits.
159    /// Inserting `other` can introduce invalid bits into `self`.
160    fn insert(&mut self, other: Self)
161    where
162        T: Copy + BitOrAssign<T>;
163
164    /// Removes all bits from `other`.
165    ///
166    /// This is a raw-bit operation.
167    /// It cannot introduce new bits, but it does not clear any other
168    /// invalid bits that may already be present.
169    fn remove(&mut self, other: Self)
170    where
171        T: Copy + Not<Output = T> + BitAndAssign<T>;
172
173    /// Toggles all bits from `other`.
174    ///
175    /// This is a raw-bit operation.
176    /// It does not validate or clear invalid bits.
177    /// Toggling `other` can introduce invalid bits into `self`.
178    fn toggle(&mut self, other: Self)
179    where
180        T: Copy + BitXorAssign<T>;
181
182    /// Inserts `other` if `value` is `true`, or removes `other` if
183    /// `value` is `false`.
184    ///
185    /// This is a raw-bit operation and follows the same invalid-bit
186    /// behavior as [`BitFlags::insert`] and [`BitFlags::remove`].
187    fn set(&mut self, other: Self, value: bool)
188    where
189        T: Copy + Not<Output = T> + BitAndAssign<T> + BitOrAssign<T>;
190
191    /// Returns the intersection of `self` and `other`.
192    ///
193    /// This is a raw-bit operation.
194    /// Invalid bits in either operand are preserved when they are set
195    /// in both operands.
196    #[must_use]
197    fn intersection(self, other: Self) -> Self
198    where
199        T: Copy + BitAnd<T, Output = T>;
200
201    /// Returns the union of `self` and `other`.
202    ///
203    /// This is a raw-bit operation.
204    /// Invalid bits in either operand are preserved.
205    #[must_use]
206    fn union(self, other: Self) -> Self
207    where
208        T: Copy + BitOr<T, Output = T>;
209
210    /// Returns the difference of `self` and `other`.
211    ///
212    /// The result contains bits that are set in `self` but not in
213    /// `other`.
214    /// This is a raw-bit operation.
215    /// Invalid bits already present in `self` are preserved unless they
216    /// are also set in `other`.
217    #[must_use]
218    fn difference(self, other: Self) -> Self
219    where
220        T: Copy + Not<Output = T> + BitAnd<T, Output = T>;
221
222    /// Returns the symmetric difference of `self` and `other`.
223    ///
224    /// The result contains bits that are set in exactly one of `self`
225    /// or `other`.
226    /// This is a raw-bit operation.
227    /// Invalid bits participate and may be preserved.
228    #[must_use]
229    fn symmetric_difference(self, other: Self) -> Self
230    where
231        T: Copy + BitXor<T, Output = T>;
232
233    /// Returns the complement of `self`.
234    ///
235    /// All valid bits not set in `self` become set, and all invalid
236    /// bits become unset.
237    /// The result always contains only valid bits.
238    #[must_use]
239    fn complement(self) -> Self
240    where
241        T: Copy + Not<Output = T> + BitAnd<T, Output = T>,
242        U: BitFlagsSpec<T>;
243}
244
245impl<T, U> BitFlagsExt<T, U> for BitFlags<T, U>
246where
247    U: ?Sized,
248{
249    #[inline]
250    fn from_flag(bit_flag: BitFlag<T, U>) -> Self
251    where
252        T: util::IntOpsExt,
253    {
254        Self::from_bit_retain(bit_flag.bit())
255    }
256
257    #[inline]
258    fn from_bit_retain(bit: u8) -> Self
259    where
260        T: util::IntOpsExt,
261    {
262        Self::from(BitFlag::from_bit_retain(bit))
263    }
264
265    #[inline]
266    fn from_bit_truncate(bit: u8) -> Self
267    where
268        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
269        U: BitFlagsSpec<T>,
270    {
271        Self::try_from_bit(bit).unwrap_or(Self::empty())
272    }
273
274    #[inline]
275    fn try_from_bit(bit: u8) -> Option<Self>
276    where
277        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
278        U: BitFlagsSpec<T>,
279    {
280        T::ONE
281            .checked_shl(u32::from(bit))
282            .and_then(Self::try_from_bits)
283    }
284
285    #[inline]
286    fn try_from_bits(bits: T) -> Option<Self>
287    where
288        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
289        U: BitFlagsSpec<T>,
290    {
291        (bits & !U::VALID_BITS_MASK == T::ZERO).then(|| Self::from_bits_retain(bits))
292    }
293
294    #[inline]
295    fn from_bits_truncate(bits: T) -> Self
296    where
297        T: BitAnd<T, Output = T>,
298        U: BitFlagsSpec<T>,
299    {
300        Self::from_bits_retain(bits & U::VALID_BITS_MASK)
301    }
302
303    #[inline]
304    fn is_empty(&self) -> bool
305    where
306        T: Copy + PartialEq + util::IntOpsExt,
307    {
308        self.bits() == T::ZERO
309    }
310
311    #[inline]
312    fn is_valid(&self) -> bool
313    where
314        T: Copy + PartialEq + Not<Output = T> + BitAnd<T, Output = T> + util::IntOpsExt,
315        U: BitFlagsSpec<T>,
316    {
317        self.bits() & !U::VALID_BITS_MASK == T::ZERO
318    }
319
320    #[inline]
321    fn intersects(&self, other: Self) -> bool
322    where
323        T: Copy + PartialEq + BitAnd<T, Output = T> + util::IntOpsExt,
324    {
325        (self.bits() & other.bits()) != T::ZERO
326    }
327
328    #[inline]
329    fn contains(&self, other: Self) -> bool
330    where
331        T: Copy + PartialEq + BitAnd<T, Output = T>,
332    {
333        (self.bits() & other.bits()) == other.bits()
334    }
335
336    #[inline]
337    fn clear(&mut self)
338    where
339        T: util::IntOpsExt,
340    {
341        *self = Self::empty();
342    }
343
344    #[inline]
345    fn truncate(&mut self)
346    where
347        T: BitAndAssign<T>,
348        U: BitFlagsSpec<T>,
349    {
350        *self.bits_mut() &= U::VALID_BITS_MASK;
351    }
352
353    #[inline]
354    fn insert(&mut self, other: Self)
355    where
356        T: Copy + BitOrAssign<T>,
357    {
358        *self.bits_mut() |= other.bits();
359    }
360
361    #[inline]
362    fn remove(&mut self, other: Self)
363    where
364        T: Copy + Not<Output = T> + BitAndAssign<T>,
365    {
366        *self.bits_mut() &= !other.bits();
367    }
368
369    #[inline]
370    fn toggle(&mut self, other: Self)
371    where
372        T: Copy + BitXorAssign<T>,
373    {
374        *self.bits_mut() ^= other.bits();
375    }
376
377    #[inline]
378    fn set(&mut self, other: Self, value: bool)
379    where
380        T: Copy + Not<Output = T> + BitAndAssign<T> + BitOrAssign<T>,
381    {
382        if value {
383            self.insert(other);
384        } else {
385            self.remove(other);
386        }
387    }
388
389    #[inline]
390    fn intersection(self, other: Self) -> Self
391    where
392        T: Copy + BitAnd<T, Output = T>,
393    {
394        Self::from_bits_retain(self.bits() & other.bits())
395    }
396
397    #[inline]
398    fn union(self, other: Self) -> Self
399    where
400        T: Copy + BitOr<T, Output = T>,
401    {
402        Self::from_bits_retain(self.bits() | other.bits())
403    }
404
405    #[inline]
406    fn difference(self, other: Self) -> Self
407    where
408        T: Copy + Not<Output = T> + BitAnd<T, Output = T>,
409    {
410        Self::from_bits_retain(self.bits() & !other.bits())
411    }
412
413    #[inline]
414    fn symmetric_difference(self, other: Self) -> Self
415    where
416        T: Copy + BitXor<T, Output = T>,
417    {
418        Self::from_bits_retain(self.bits() ^ other.bits())
419    }
420
421    #[inline]
422    fn complement(self) -> Self
423    where
424        T: Copy + Not<Output = T> + BitAnd<T, Output = T>,
425        U: BitFlagsSpec<T>,
426    {
427        Self::from_bits_retain(!self.bits() & U::VALID_BITS_MASK)
428    }
429}