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}