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
188 khora_bitflags! {
190 pub struct TestFlags: u32 {
192 const FLAG_A = 1 << 0;
193 const FLAG_B = 1 << 1;
194 const FLAG_C = 1 << 2;
195 const FLAG_D = 1 << 3;
196 const COMBINED_AC = Self::FLAG_A.bits() | Self::FLAG_C.bits();
197 const CUSTOM_HIGH_BIT = 1 << 20;
198 const NONE_FLAG = 0; }
200 }
201
202 #[test]
203 fn test_empty_flags() {
204 let flags = TestFlags::EMPTY;
205 assert_eq!(flags.bits(), 0);
206 assert!(flags.contains(TestFlags::EMPTY));
207 assert!(!flags.contains(TestFlags::FLAG_A));
208 assert_eq!(TestFlags::default().bits(), 0, "Default should be empty");
209 assert_eq!(format!("{flags:?}"), "TestFlags { EMPTY }");
210 }
211
212 #[test]
213 fn test_single_flag() {
214 let flags = TestFlags::FLAG_A;
215 assert_eq!(flags.bits(), 1);
216 assert!(flags.contains(TestFlags::FLAG_A));
217 assert!(!flags.contains(TestFlags::FLAG_B));
218 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A }");
219 }
220
221 #[test]
222 fn test_multiple_flags() {
223 let flags = TestFlags::FLAG_A | TestFlags::FLAG_C;
224 assert_eq!(flags.bits(), 0b101); assert!(flags.contains(TestFlags::FLAG_A));
226 assert!(!flags.contains(TestFlags::FLAG_B));
227 assert!(flags.contains(TestFlags::FLAG_C));
228 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
229 }
230
231 #[test]
232 fn test_combined_constant() {
233 let flags = TestFlags::COMBINED_AC;
234 assert_eq!(
235 flags.bits(),
236 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
237 );
238 assert!(flags.contains(TestFlags::FLAG_A));
239 assert!(flags.contains(TestFlags::FLAG_C));
240 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
241 }
242
243 #[test]
244 fn test_from_bits_truncate_and_bits() {
245 let flags = TestFlags::from_bits_truncate(5);
246 assert_eq!(flags.bits(), 5);
247 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
248
249 let unknown_bits = TestFlags::from_bits_truncate(0b10000); assert_eq!(unknown_bits.bits(), 16);
252 assert_eq!(format!("{unknown_bits:?}"), "TestFlags { UNKNOWN(0x10) }");
253 }
254
255 #[test]
256 fn test_contains() {
257 let all_defined =
258 TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C | TestFlags::FLAG_D;
259 assert!(all_defined.contains(TestFlags::FLAG_A));
260 assert!(all_defined.contains(TestFlags::FLAG_A | TestFlags::FLAG_C));
261 assert!(!all_defined.contains(TestFlags::CUSTOM_HIGH_BIT));
262 assert!(!all_defined.contains(TestFlags::FLAG_A | TestFlags::CUSTOM_HIGH_BIT));
263 assert!(all_defined.contains(TestFlags::EMPTY));
264 }
265
266 #[test]
267 fn test_intersects() {
268 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));
275 assert!(!flags1.intersects(TestFlags::EMPTY)); }
277
278 #[test]
279 fn test_mutable_operations_insert() {
280 let mut flags = TestFlags::FLAG_A;
281 flags.insert(TestFlags::FLAG_B);
282 assert_eq!(
283 flags.bits(),
284 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
285 );
286 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_B }");
287 }
288
289 #[test]
290 fn test_mutable_operations_remove() {
291 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B;
292 flags.remove(TestFlags::FLAG_A);
293 assert_eq!(flags.bits(), TestFlags::FLAG_B.bits());
294 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_B }");
295
296 flags.remove(TestFlags::FLAG_B | TestFlags::FLAG_D); assert_eq!(flags.bits(), TestFlags::EMPTY.bits());
298 assert_eq!(format!("{flags:?}"), "TestFlags { EMPTY }");
299 }
300
301 #[test]
302 fn test_mutable_operations_toggle() {
303 let mut flags = TestFlags::FLAG_A;
304 flags.toggle(TestFlags::FLAG_C); assert_eq!(
306 flags.bits(),
307 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
308 );
309 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
310
311 flags.toggle(TestFlags::FLAG_A); assert_eq!(flags.bits(), TestFlags::FLAG_C.bits());
313 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_C }");
314 }
315
316 #[test]
317 fn test_immutable_operations_with() {
318 let initial = TestFlags::FLAG_A;
319 let with_b = initial.with(TestFlags::FLAG_B);
320 assert_eq!(
321 with_b.bits(),
322 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
323 );
324 assert_eq!(format!("{with_b:?}"), "TestFlags { FLAG_A | FLAG_B }");
325 assert_eq!(
326 initial.bits(),
327 TestFlags::FLAG_A.bits(),
328 "Original should be unchanged"
329 );
330 }
331
332 #[test]
333 fn test_immutable_operations_without() {
334 let initial = TestFlags::FLAG_A | TestFlags::FLAG_B;
335 let without_a = initial.without(TestFlags::FLAG_A);
336 assert_eq!(without_a.bits(), TestFlags::FLAG_B.bits());
337 assert_eq!(format!("{without_a:?}"), "TestFlags { FLAG_B }");
338 assert_eq!(
339 initial.bits(),
340 (TestFlags::FLAG_A | TestFlags::FLAG_B).bits(),
341 "Original should be unchanged"
342 );
343 }
344
345 #[test]
346 fn test_bitwise_or_operator() {
347 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
348 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
349 let result = f1 | f2;
350 assert_eq!(
351 result.bits(),
352 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits() | TestFlags::FLAG_C.bits()
353 );
354 assert_eq!(
355 format!("{result:?}"),
356 "TestFlags { FLAG_A | FLAG_B | FLAG_C }"
357 );
358 }
359
360 #[test]
361 fn test_bitwise_and_operator() {
362 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
363 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
364 let result = f1 & f2;
365 assert_eq!(result.bits(), TestFlags::FLAG_B.bits());
366 assert_eq!(format!("{result:?}"), "TestFlags { FLAG_B }");
367 }
368
369 #[test]
370 fn test_bitwise_xor_operator() {
371 let f1 = TestFlags::FLAG_A | TestFlags::FLAG_B;
372 let f2 = TestFlags::FLAG_B | TestFlags::FLAG_C;
373 let result = f1 ^ f2;
374 assert_eq!(
375 result.bits(),
376 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
377 );
378 assert_eq!(format!("{result:?}"), "TestFlags { FLAG_A | FLAG_C }");
379 }
380
381 #[test]
382 fn test_bitwise_not_operator() {
383 let flags = TestFlags::FLAG_A;
384 let result = !flags;
385 assert_eq!(result.bits(), !TestFlags::FLAG_A.bits()); }
390
391 #[test]
392 fn test_assign_or_operator() {
393 let mut flags = TestFlags::FLAG_A;
394 flags |= TestFlags::FLAG_B;
395 assert_eq!(
396 flags.bits(),
397 TestFlags::FLAG_A.bits() | TestFlags::FLAG_B.bits()
398 );
399 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_B }");
400 }
401
402 #[test]
403 fn test_assign_and_operator() {
404 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C; flags &= TestFlags::FLAG_B | TestFlags::FLAG_D;
408 assert_eq!(flags.bits(), TestFlags::FLAG_B.bits());
409 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_B }");
410 }
411
412 #[test]
413 fn test_assign_xor_operator() {
414 let mut flags = TestFlags::FLAG_A | TestFlags::FLAG_B | TestFlags::FLAG_C;
415 flags ^= TestFlags::FLAG_B; assert_eq!(
417 flags.bits(),
418 TestFlags::FLAG_A.bits() | TestFlags::FLAG_C.bits()
419 );
420 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A | FLAG_C }");
421 }
422
423 #[test]
424 fn test_debug_formatting_high_bit() {
425 let flags = TestFlags::CUSTOM_HIGH_BIT;
426 assert_eq!(format!("{flags:?}"), "TestFlags { CUSTOM_HIGH_BIT }");
427 }
428
429 #[test]
430 fn test_debug_formatting_mixed_known_and_unknown() {
431 let flags = TestFlags::FLAG_A | TestFlags::from_bits_truncate(1 << 8); assert_eq!(
434 format!("{flags:?}"),
435 "TestFlags { FLAG_A | UNKNOWN(0x100) }"
436 );
437
438 let flags_more_unknown =
439 TestFlags::FLAG_B | TestFlags::from_bits_truncate((1 << 8) | (1 << 9)); assert_eq!(
441 format!("{flags_more_unknown:?}"),
442 "TestFlags { FLAG_B | UNKNOWN(0x300) }"
443 );
444 }
445
446 #[test]
447 fn test_debug_formatting_only_unknown() {
448 let flags = TestFlags::from_bits_truncate((1 << 4) | (1 << 5));
455 assert_eq!(format!("{flags:?}"), "TestFlags { UNKNOWN(0x30) }");
456
457 let flags_single_unknown = TestFlags::from_bits_truncate(1 << 4); assert_eq!(
460 format!("{flags_single_unknown:?}"),
461 "TestFlags { UNKNOWN(0x10) }"
462 );
463 }
464
465 #[test]
466 fn test_none_flag_value() {
467 let flags = TestFlags::FLAG_A | TestFlags::NONE_FLAG;
469 assert_eq!(flags.bits(), TestFlags::FLAG_A.bits());
470 assert_eq!(format!("{flags:?}"), "TestFlags { FLAG_A }");
471
472 let flags_empty = TestFlags::NONE_FLAG;
473 assert_eq!(flags_empty.bits(), 0);
474 assert_eq!(format!("{flags_empty:?}"), "TestFlags { EMPTY }");
475 }
476}