khora_core/utils/
bitflags.rs1#[macro_export]
17#[doc(hidden)]
18macro_rules! khora_bitflags {
19 (
20 $(#[$attr:meta])*
21 $vis:vis struct $name:ident: $ty:ty {
22 $(
23 $(#[$flag_attr:meta])*
24 const $flag_name:ident = $flag_value:expr;
25 )*
26 }
27 ) => {
28 $(#[$attr])*
29 #[derive(Clone, Copy, PartialEq, Eq, Hash, Default)]
30 $vis struct $name {
31 pub(crate) bits: $ty,
32 }
33
34 impl $name {
35 pub const EMPTY: Self = Self { bits: 0 };
37
38 pub const fn from_bits_truncate(bits: $ty) -> Self {
41 Self { bits }
42 }
43
44 pub const fn bits(&self) -> $ty {
46 self.bits
47 }
48
49 pub const fn contains(&self, other: Self) -> bool {
51 (self.bits & other.bits) == other.bits
52 }
53
54 pub const fn intersects(&self, other: Self) -> bool {
56 (self.bits & other.bits) != 0
57 }
58
59 pub fn insert(&mut self, other: Self) {
61 self.bits |= other.bits;
62 }
63
64 pub fn remove(&mut self, other: Self) {
66 self.bits &= !other.bits;
67 }
68
69 pub fn toggle(&mut self, other: Self) {
71 self.bits ^= other.bits;
72 }
73
74 #[must_use]
76 pub const fn with(mut self, other: Self) -> Self {
77 self.bits |= other.bits;
78 self
79 }
80
81 #[must_use]
83 pub const fn without(mut self, other: Self) -> Self {
84 self.bits &= !other.bits;
85 self
86 }
87
88 $(
90 $(#[$flag_attr])*
91 pub const $flag_name: Self = Self { bits: $flag_value };
92 )*
93 }
94
95 impl core::ops::BitOr for $name {
97 type Output = Self;
98 fn bitor(self, other: Self) -> Self {
99 Self { bits: self.bits | other.bits }
100 }
101 }
102
103 impl core::ops::BitAnd for $name {
104 type Output = Self;
105 fn bitand(self, other: Self) -> Self {
106 Self { bits: self.bits & other.bits }
107 }
108 }
109
110 impl core::ops::BitXor for $name {
111 type Output = Self;
112 fn bitxor(self, other: Self) -> Self {
113 Self { bits: self.bits ^ other.bits }
114 }
115 }
116
117 impl core::ops::Not for $name {
118 type Output = Self;
119 fn not(self) -> Self {
120 Self { bits: !self.bits }
121 }
122 }
123
124 impl core::ops::BitOrAssign for $name {
125 fn bitor_assign(&mut self, other: Self) {
126 self.bits |= other.bits;
127 }
128 }
129
130 impl core::ops::BitAndAssign for $name {
131 fn bitand_assign(&mut self, other: Self) {
132 self.bits &= other.bits;
133 }
134 }
135
136 impl core::ops::BitXorAssign for $name {
137 fn bitxor_assign(&mut self, other: Self) {
138 self.bits ^= other.bits;
139 }
140 }
141
142 impl core::fmt::Debug for $name {
144 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
145 let mut bits = self.bits;
146 let mut first_flag = true;
147
148 write!(f, "{} {{ ", stringify!($name))?;
149
150 $(
151 if ($flag_value != 0) && (bits & $flag_value) == $flag_value {
154 if !first_flag {
155 write!(f, " | ")?;
156 }
157 write!(f, "{}", stringify!($flag_name))?;
158 bits &= !$flag_value; first_flag = false;
160 }
161 )*
162
163 if bits != 0 {
165 if !first_flag {
166 write!(f, " | ")?;
167 }
168 write!(f, "UNKNOWN({:#x})", bits)?;
169 first_flag = false;
170 }
171
172 if self.bits == 0 && first_flag {
176 write!(f, "EMPTY")?;
177 }
178
179 write!(f, " }}")
180 }
181 }
182 };
183}
184
185#[cfg(test)]
186mod tests {
187 use crate::khora_bitflags;
189
190 khora_bitflags! {
192 pub struct TestFlags: u32 {
194 const FLAG_A = 1 << 0;
195 const FLAG_B = 1 << 1;
196 const FLAG_C = 1 << 2;
197 const FLAG_D = 1 << 3;
198 const COMBINED_AC = Self::FLAG_A.bits() | Self::FLAG_C.bits();
199 const CUSTOM_HIGH_BIT = 1 << 20;
200 const NONE_FLAG = 0; }
202 }
203
204 #[test]
205 fn test_empty_flags() {
206 let flags = TestFlags::EMPTY;
207 assert_eq!(flags.bits(), 0);
208 assert!(flags.contains(TestFlags::EMPTY));
209 assert!(!flags.contains(TestFlags::FLAG_A));
210 assert_eq!(TestFlags::default().bits(), 0, "Default should be empty");
211 assert_eq!(format!("{flags:?}"), "TestFlags { EMPTY }");
212 }
213
214 #[test]
215 fn test_single_flag() {
216 let flags = TestFlags::FLAG_A;
217 assert_eq!(flags.bits(), 1);
218 assert!(flags.contains(TestFlags::FLAG_A));
219 assert!(!flags.contains(TestFlags::FLAG_B));
220 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A }");
221 }
222
223 #[test]
224 fn test_multiple_flags() {
225 let flags = TestFlags::FLAG_A | TestFlags::FLAG_C;
226 assert_eq!(flags.bits(), 0b101); assert!(flags.contains(TestFlags::FLAG_A));
228 assert!(!flags.contains(TestFlags::FLAG_B));
229 assert!(flags.contains(TestFlags::FLAG_C));
230 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
231 }
232
233 #[test]
234 fn test_combined_constant() {
235 let flags = TestFlags::COMBINED_AC;
236 assert_eq!(
237 flags.bits(),
238 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
239 );
240 assert!(flags.contains(TestFlags::FLAG_A));
241 assert!(flags.contains(TestFlags::FLAG_C));
242 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
243 }
244
245 #[test]
246 fn test_from_bits_truncate_and_bits() {
247 let flags = TestFlags::from_bits_truncate(5);
248 assert_eq!(flags.bits(), 5);
249 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
250
251 let unknown_bits = TestFlags::from_bits_truncate(0b10000); assert_eq!(unknown_bits.bits(), 16);
254 assert_eq!(format!("{unknown_bits:?}"), "TestFlags { UNKNOWN(0x10) }");
255 }
256
257 #[test]
258 fn test_contains() {
259 let all_defined =
260 TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C | TestFlags::FLAG_D;
261 assert!(all_defined.contains(TestFlags::FLAG_A));
262 assert!(all_defined.contains(TestFlags::FLAG_A | TestFlags::FLAG_C));
263 assert!(!all_defined.contains(TestFlags::CUSTOM_HIGH_BIT));
264 assert!(!all_defined.contains(TestFlags::FLAG_A | TestFlags::CUSTOM_HIGH_BIT));
265 assert!(all_defined.contains(TestFlags::EMPTY));
266 }
267
268 #[test]
269 fn test_intersects() {
270 let flags1 = TestFlags::FLAG_A | TestFlags::FLAG_B; let flags2 = TestFlags::FLAG_B | TestFlags::FLAG_C; let flags3 = TestFlags::FLAG_C | TestFlags::FLAG_D; assert!(flags1.intersects(flags2)); assert!(!flags1.intersects(flags3)); assert!(flags1.intersects(TestFlags::FLAG_A));
277 assert!(!flags1.intersects(TestFlags::EMPTY)); }
279
280 #[test]
281 fn test_mutable_operations_insert() {
282 let mut flags = TestFlags::FLAG_A;
283 flags.insert(TestFlags::FLAG_B);
284 assert_eq!(
285 flags.bits(),
286 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
287 );
288 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_B }");
289 }
290
291 #[test]
292 fn test_mutable_operations_remove() {
293 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B;
294 flags.remove(TestFlags::FLAG_A);
295 assert_eq!(flags.bits(), TestFlags::FLAG_B.bits());
296 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_B }");
297
298 flags.remove(TestFlags::FLAG_B | TestFlags::FLAG_D); assert_eq!(flags.bits(), TestFlags::EMPTY.bits());
300 assert_eq!(format!("{flags:?}"), "TestFlags { EMPTY }");
301 }
302
303 #[test]
304 fn test_mutable_operations_toggle() {
305 let mut flags = TestFlags::FLAG_A;
306 flags.toggle(TestFlags::FLAG_C); assert_eq!(
308 flags.bits(),
309 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
310 );
311 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
312
313 flags.toggle(TestFlags::FLAG_A); assert_eq!(flags.bits(), TestFlags::FLAG_C.bits());
315 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_C }");
316 }
317
318 #[test]
319 fn test_immutable_operations_with() {
320 let initial = TestFlags::FLAG_A;
321 let with_b = initial.with(TestFlags::FLAG_B);
322 assert_eq!(
323 with_b.bits(),
324 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
325 );
326 assert_eq!(format!("{with_b:?}"), "TestFlags { FLAG_A | FLAG_B }");
327 assert_eq!(
328 initial.bits(),
329 TestFlags::FLAG_A.bits(),
330 "Original should be unchanged"
331 );
332 }
333
334 #[test]
335 fn test_immutable_operations_without() {
336 let initial = TestFlags::FLAG_A | TestFlags::FLAG_B;
337 let without_a = initial.without(TestFlags::FLAG_A);
338 assert_eq!(without_a.bits(), TestFlags::FLAG_B.bits());
339 assert_eq!(format!("{without_a:?}"), "TestFlags { FLAG_B }");
340 assert_eq!(
341 initial.bits(),
342 (TestFlags::FLAG_A | TestFlags::FLAG_B).bits(),
343 "Original should be unchanged"
344 );
345 }
346
347 #[test]
348 fn test_bitwise_or_operator() {
349 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
350 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
351 let result = f1 | f2;
352 assert_eq!(
353 result.bits(),
354 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits() | TestFlags::FLAG_C.bits()
355 );
356 assert_eq!(
357 format!("{result:?}"),
358 "TestFlags { FLAG_A | FLAG_B | FLAG_C }"
359 );
360 }
361
362 #[test]
363 fn test_bitwise_and_operator() {
364 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
365 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
366 let result = f1 & f2;
367 assert_eq!(result.bits(), TestFlags::FLAG_B.bits());
368 assert_eq!(format!("{result:?}"), "TestFlags { FLAG_B }");
369 }
370
371 #[test]
372 fn test_bitwise_xor_operator() {
373 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
374 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
375 let result = f1 ^ f2;
376 assert_eq!(
377 result.bits(),
378 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
379 );
380 assert_eq!(format!("{result:?}"), "TestFlags { FLAG_A | FLAG_C }");
381 }
382
383 #[test]
384 fn test_bitwise_not_operator() {
385 let flags = TestFlags::FLAG_A;
386 let result = !flags;
387 assert_eq!(result.bits(), !TestFlags::FLAG_A.bits()); }
392
393 #[test]
394 fn test_assign_or_operator() {
395 let mut flags = TestFlags::FLAG_A;
396 flags |= TestFlags::FLAG_B;
397 assert_eq!(
398 flags.bits(),
399 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
400 );
401 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_B }");
402 }
403
404 #[test]
405 fn test_assign_and_operator() {
406 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C; flags &= TestFlags::FLAG_B | TestFlags::FLAG_D;
410 assert_eq!(flags.bits(), TestFlags::FLAG_B.bits());
411 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_B }");
412 }
413
414 #[test]
415 fn test_assign_xor_operator() {
416 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C;
417 flags ^= TestFlags::FLAG_B; assert_eq!(
419 flags.bits(),
420 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
421 );
422 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
423 }
424
425 #[test]
426 fn test_debug_formatting_high_bit() {
427 let flags = TestFlags::CUSTOM_HIGH_BIT;
428 assert_eq!(format!("{flags:?}"), "TestFlags { CUSTOM_HIGH_BIT }");
429 }
430
431 #[test]
432 fn test_debug_formatting_mixed_known_and_unknown() {
433 let flags = TestFlags::FLAG_A | TestFlags::from_bits_truncate(1 << 8); assert_eq!(
436 format!("{flags:?}"),
437 "TestFlags { FLAG_A | UNKNOWN(0x100) }"
438 );
439
440 let flags_more_unknown =
441 TestFlags::FLAG_B | TestFlags::from_bits_truncate((1 << 8) | (1 << 9)); assert_eq!(
443 format!("{flags_more_unknown:?}"),
444 "TestFlags { FLAG_B | UNKNOWN(0x300) }"
445 );
446 }
447
448 #[test]
449 fn test_debug_formatting_only_unknown() {
450 let flags = TestFlags::from_bits_truncate((1 << 4) | (1 << 5));
457 assert_eq!(format!("{flags:?}"), "TestFlags { UNKNOWN(0x30) }");
458
459 let flags_single_unknown = TestFlags::from_bits_truncate(1 << 4); assert_eq!(
462 format!("{flags_single_unknown:?}"),
463 "TestFlags { UNKNOWN(0x10) }"
464 );
465 }
466
467 #[test]
468 fn test_none_flag_value() {
469 let flags = TestFlags::FLAG_A | TestFlags::NONE_FLAG;
471 assert_eq!(flags.bits(), TestFlags::FLAG_A.bits());
472 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A }");
473
474 let flags_empty = TestFlags::NONE_FLAG;
475 assert_eq!(flags_empty.bits(), 0);
476 assert_eq!(format!("{flags_empty:?}"), "TestFlags { EMPTY }");
477 }
478}