1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
2#[repr(transparent)]
3pub struct FieldMask(pub u64);
4
5impl FieldMask {
6 #[inline]
7 #[must_use]
8 pub const fn empty() -> Self {
9 Self(0)
10 }
11 #[inline]
12 #[must_use]
13 pub const fn is_empty(&self) -> bool {
14 self.0 == 0
15 }
16 #[inline]
17 #[must_use]
18 pub const fn with_bit(self, bit: FieldBit) -> Self {
19 Self(self.0 | (1u64 << bit.get()))
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
27#[repr(transparent)]
28pub struct CompletedMask(pub u64);
29
30impl CompletedMask {
31 #[inline]
32 #[must_use]
33 pub const fn empty() -> Self {
34 Self(0)
35 }
36 #[inline]
37 #[must_use]
38 pub const fn is_empty(&self) -> bool {
39 self.0 == 0
40 }
41 #[inline]
42 #[must_use]
43 pub const fn with_bit(self, bit: FieldBit) -> Self {
44 Self(self.0 | (1u64 << bit.get()))
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
50#[repr(transparent)]
51pub struct FieldBit(u8);
52
53impl FieldBit {
54 #[inline]
57 pub const fn new_checked(value: u8) -> Result<Self, MaskError> {
58 if value < 64 {
59 Ok(Self(value))
60 } else {
61 Err(MaskError::OutOfRange)
62 }
63 }
64 #[inline]
65 #[must_use]
66 pub const fn new_unchecked(value: u8) -> Self {
67 Self(value)
68 }
69 #[inline]
70 #[must_use]
71 pub const fn get(self) -> u8 {
72 self.0
73 }
74}
75
76#[derive(Debug, Clone, Copy, PartialEq, Eq)]
77pub enum MaskError {
78 OutOfRange,
79}
80
81impl core::fmt::Display for MaskError {
82 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
83 match self {
84 Self::OutOfRange => write!(f, "FieldBit must be in range [0, 63]"),
85 }
86 }
87}
88
89impl std::error::Error for MaskError {}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94
95 #[test]
100 fn with_bit_matches_pow2_for_every_bit() {
101 for b in 0u8..64u8 {
102 let bit = FieldBit::new_checked(b).unwrap();
103 let m = FieldMask::empty().with_bit(bit);
104 assert_eq!(m.0, 1u64 << b, "FieldMask bit {b} mismatch");
105 let cm = CompletedMask::empty().with_bit(bit);
106 assert_eq!(cm.0, 1u64 << b, "CompletedMask bit {b} mismatch");
107 }
108 }
109
110 #[test]
113 fn field_bit_range_contract() {
114 for v in 0u8..64u8 {
115 assert_eq!(FieldBit::new_checked(v).unwrap().get(), v);
116 }
117 for v in 64u8..=200u8 {
118 assert_eq!(FieldBit::new_checked(v), Err(MaskError::OutOfRange));
119 }
120 }
121}