1use std::fmt::{Display, Write};
2
3use super::onescomplement::unsigned::Unsigned36Bit;
4use super::quarters::Quarter;
5
6#[repr(u8)]
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
8pub enum BitPos {
9 B1 = 0,
10 B2 = 1,
11 B3 = 2,
12 B4 = 3,
13 B5 = 4,
14 B6 = 5,
15 B7 = 6,
16 B8 = 7,
17 B9 = 8,
18}
19
20impl Display for BitPos {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 f.write_char(match self {
23 BitPos::B1 => '1',
24 BitPos::B2 => '2',
25 BitPos::B3 => '3',
26 BitPos::B4 => '4',
27 BitPos::B5 => '5',
28 BitPos::B6 => '6',
29 BitPos::B7 => '7',
30 BitPos::B8 => '8',
31 BitPos::B9 => '9',
32 })
33 }
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
37pub struct BitSelector {
38 pub quarter: Quarter,
39 pub bitpos: BitPos,
45}
46
47impl BitSelector {
48 #[must_use]
49 pub const fn raw_mask(&self) -> u64 {
50 let shift = (self.quarter as u32) * 9 + (self.bitpos as u32);
51 1_u64 << shift
52 }
53
54 #[must_use]
55 pub fn mask(&self) -> Unsigned36Bit {
56 Unsigned36Bit::try_from(self.raw_mask())
57 .expect("bit selector mask values cannot be outside the range of Unsigned36Bit")
58 }
59}
60
61impl Display for BitSelector {
62 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63 write!(f, "{}.{}", &self.quarter, &self.bitpos)
64 }
65}
66
67#[cfg(test)]
68const fn bit_select_mask(quarter: Quarter, bitpos: BitPos) -> u64 {
69 BitSelector { quarter, bitpos }.raw_mask()
70}
71
72#[test]
73fn test_bit_select_mask_q1() {
74 assert_eq!(
75 bit_select_mask(Quarter::Q1, BitPos::B1),
76 0o001_u64,
77 "failed for bit 1.1"
78 );
79 assert_eq!(
80 bit_select_mask(Quarter::Q1, BitPos::B2),
81 0o002_u64,
82 "failed for bit 1.2"
83 );
84 assert_eq!(
85 bit_select_mask(Quarter::Q1, BitPos::B3),
86 0o004_u64,
87 "failed for bit 1.3"
88 );
89 assert_eq!(
90 bit_select_mask(Quarter::Q1, BitPos::B4),
91 0o010_u64,
92 "failed for bit 1.4"
93 );
94 assert_eq!(
95 bit_select_mask(Quarter::Q1, BitPos::B5),
96 0o020_u64,
97 "failed for bit 1.5"
98 );
99 assert_eq!(
100 bit_select_mask(Quarter::Q1, BitPos::B6),
101 0o040_u64,
102 "failed for bit 1.6"
103 );
104 assert_eq!(
105 bit_select_mask(Quarter::Q1, BitPos::B7),
106 0o100_u64,
107 "failed for bit 1.7"
108 );
109 assert_eq!(
110 bit_select_mask(Quarter::Q1, BitPos::B8),
111 0o200_u64,
112 "failed for bit 1.8"
113 );
114 assert_eq!(
115 bit_select_mask(Quarter::Q1, BitPos::B9),
116 0o400_u64,
117 "failed for bit 1.9"
118 );
119}
120
121#[test]
122fn test_bit_select_mask_q2() {
123 assert_eq!(
124 bit_select_mask(Quarter::Q2, BitPos::B1),
125 0o001_000_u64,
126 "failed for bit 2.1"
127 );
128 assert_eq!(
129 bit_select_mask(Quarter::Q2, BitPos::B2),
130 0o002_000_u64,
131 "failed for bit 2.2"
132 );
133 assert_eq!(
134 bit_select_mask(Quarter::Q2, BitPos::B3),
135 0o004_000_u64,
136 "failed for bit 2.3"
137 );
138 assert_eq!(
139 bit_select_mask(Quarter::Q2, BitPos::B4),
140 0o010_000_u64,
141 "failed for bit 2.4"
142 );
143 assert_eq!(
144 bit_select_mask(Quarter::Q2, BitPos::B5),
145 0o020_000_u64,
146 "failed for bit 2.5"
147 );
148 assert_eq!(
149 bit_select_mask(Quarter::Q2, BitPos::B6),
150 0o040_000_u64,
151 "failed for bit 2.6"
152 );
153 assert_eq!(
154 bit_select_mask(Quarter::Q2, BitPos::B7),
155 0o100_000_u64,
156 "failed for bit 2.7"
157 );
158 assert_eq!(
159 bit_select_mask(Quarter::Q2, BitPos::B8),
160 0o200_000_u64,
161 "failed for bit 2.8"
162 );
163 assert_eq!(
164 bit_select_mask(Quarter::Q2, BitPos::B9),
165 0o400_000_u64,
166 "failed for bit 2.9"
167 );
168}
169
170#[test]
171fn test_bit_select_mask_q3() {
172 assert_eq!(
173 bit_select_mask(Quarter::Q3, BitPos::B1),
174 0o001_000_000_u64,
175 "failed for bit 3.1"
176 );
177 assert_eq!(
178 bit_select_mask(Quarter::Q3, BitPos::B2),
179 0o002_000_000_u64,
180 "failed for bit 3.2"
181 );
182 assert_eq!(
183 bit_select_mask(Quarter::Q3, BitPos::B3),
184 0o004_000_000_u64,
185 "failed for bit 3.3"
186 );
187 assert_eq!(
188 bit_select_mask(Quarter::Q3, BitPos::B4),
189 0o010_000_000_u64,
190 "failed for bit 3.4"
191 );
192 assert_eq!(
193 bit_select_mask(Quarter::Q3, BitPos::B5),
194 0o020_000_000_u64,
195 "failed for bit 3.5"
196 );
197 assert_eq!(
198 bit_select_mask(Quarter::Q3, BitPos::B6),
199 0o040_000_000_u64,
200 "failed for bit 3.6"
201 );
202 assert_eq!(
203 bit_select_mask(Quarter::Q3, BitPos::B7),
204 0o100_000_000_u64,
205 "failed for bit 3.7"
206 );
207 assert_eq!(
208 bit_select_mask(Quarter::Q3, BitPos::B8),
209 0o200_000_000_u64,
210 "failed for bit 3.8"
211 );
212 assert_eq!(
213 bit_select_mask(Quarter::Q3, BitPos::B9),
214 0o400_000_000_u64,
215 "failed for bit 3.9"
216 );
217}
218
219#[test]
220fn test_bit_select_mask_q4() {
221 assert_eq!(
222 bit_select_mask(Quarter::Q4, BitPos::B1),
223 0o001_000_000_000_u64,
224 "failed for bit 4.1"
225 );
226 assert_eq!(
227 bit_select_mask(Quarter::Q4, BitPos::B2),
228 0o002_000_000_000_u64,
229 "failed for bit 4.2"
230 );
231 assert_eq!(
232 bit_select_mask(Quarter::Q4, BitPos::B3),
233 0o004_000_000_000_u64,
234 "failed for bit 4.3"
235 );
236 assert_eq!(
237 bit_select_mask(Quarter::Q4, BitPos::B4),
238 0o010_000_000_000_u64,
239 "failed for bit 4.4"
240 );
241 assert_eq!(
242 bit_select_mask(Quarter::Q4, BitPos::B5),
243 0o020_000_000_000_u64,
244 "failed for bit 4.5"
245 );
246 assert_eq!(
247 bit_select_mask(Quarter::Q4, BitPos::B6),
248 0o040_000_000_000_u64,
249 "failed for bit 4.6"
250 );
251 assert_eq!(
252 bit_select_mask(Quarter::Q4, BitPos::B7),
253 0o100_000_000_000_u64,
254 "failed for bit 4.7"
255 );
256 assert_eq!(
257 bit_select_mask(Quarter::Q4, BitPos::B8),
258 0o200_000_000_000_u64,
259 "failed for bit 4.8"
260 );
261 assert_eq!(
262 bit_select_mask(Quarter::Q4, BitPos::B9),
263 0o400_000_000_000_u64,
264 "failed for bit 4.9"
265 );
266}
267
268#[cfg(test)]
269fn all_bit_selectors() -> Vec<BitSelector> {
270 let mut result = Vec::with_capacity(36);
271 for quarter in [Quarter::Q1, Quarter::Q2, Quarter::Q3, Quarter::Q4] {
272 for bitpos in [
273 BitPos::B1,
274 BitPos::B2,
275 BitPos::B3,
276 BitPos::B4,
277 BitPos::B5,
278 BitPos::B6,
279 BitPos::B7,
280 BitPos::B8,
281 BitPos::B9,
282 ] {
283 result.push(BitSelector { quarter, bitpos });
284 }
285 }
286 result
287}
288
289#[must_use]
290pub const fn bit_select(value: Unsigned36Bit, selector: BitSelector) -> bool {
291 value.bits & selector.raw_mask() != 0
292}
293
294#[test]
295fn test_bit_select() {
296 for (bitpos, selector) in all_bit_selectors().into_iter().enumerate() {
297 let just_that_bit: Unsigned36Bit =
298 Unsigned36Bit::try_from(1_u64 << bitpos).expect("test bit should not be out of range");
299 for selector_to_test in all_bit_selectors() {
300 let found_value: bool = bit_select(just_that_bit, selector_to_test);
301 if selector_to_test == selector {
302 assert!(
304 found_value,
305 "bit {selector_to_test} should be set in {just_that_bit:012o}"
306 );
307 } else {
308 assert!(
309 !found_value,
310 "bit {selector_to_test} should be unset in {just_that_bit:012o}"
311 );
312 }
313 }
314 }
315}