nexus_bits/flag.rs
1//! Single-bit flag extraction and packing.
2
3/// A single-bit flag within a packed integer.
4///
5/// Simpler than `BitField` for boolean flags - no overflow checking needed.
6///
7/// # Example
8///
9/// ```
10/// use nexus_bits::Flag;
11///
12/// const IS_BUY: Flag<u64> = Flag::<u64>::new(0);
13/// const IS_IOC: Flag<u64> = Flag::<u64>::new(1);
14///
15/// let mut flags: u64 = 0;
16/// flags = IS_BUY.set(flags);
17/// flags = IS_IOC.set(flags);
18///
19/// assert!(IS_BUY.is_set(flags));
20/// assert!(IS_IOC.is_set(flags));
21///
22/// flags = IS_IOC.clear(flags);
23/// assert!(!IS_IOC.is_set(flags));
24/// ```
25#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26pub struct Flag<T> {
27 bit: u32,
28 mask: T,
29}
30
31macro_rules! impl_flag {
32 ($($ty:ty),*) => {
33 $(
34 impl Flag<$ty> {
35 /// Creates a flag at bit position `bit`.
36 ///
37 /// # Panics
38 ///
39 /// Panics if `bit` >= type's bit width.
40 #[inline]
41 pub const fn new(bit: u32) -> Self {
42 assert!(bit < <$ty>::BITS, "bit position exceeds integer bounds");
43 let mask = 1 << bit;
44 Self { bit, mask }
45 }
46
47 /// Bit position.
48 #[inline]
49 pub const fn bit(self) -> u32 {
50 self.bit
51 }
52
53 /// Mask with 1 at flag position.
54 #[inline]
55 pub const fn mask(self) -> $ty {
56 self.mask
57 }
58
59 /// Returns true if flag is set.
60 #[inline]
61 pub const fn is_set(self, val: $ty) -> bool {
62 (val & self.mask) != 0
63 }
64
65 /// Set flag to 1.
66 #[inline]
67 pub const fn set(self, val: $ty) -> $ty {
68 val | self.mask
69 }
70
71 /// Set flag to 0.
72 #[inline]
73 pub const fn clear(self, val: $ty) -> $ty {
74 val & !self.mask
75 }
76
77 /// Flip flag.
78 #[inline]
79 pub const fn toggle(self, val: $ty) -> $ty {
80 val ^ self.mask
81 }
82
83 /// Set flag to given boolean value.
84 #[inline]
85 pub const fn set_to(self, val: $ty, enabled: bool) -> $ty {
86 if enabled {
87 self.set(val)
88 } else {
89 self.clear(val)
90 }
91 }
92 }
93 )*
94 };
95}
96
97impl_flag!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);