base/
bitselect.rs

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    /// `bitpos` values 1 to 9 inclusive are normal bit positions in a
40    /// quarter.  0 is a valid value but not a valid bit (so a default
41    /// will be used when SKM tests bit 0).  10 is the meta bit.  11
42    /// is the parity bit stored in memory.  12 is the parity value
43    /// computed from the bits stored in memory.
44    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                // The quarter and bit number is the one we had set, so the value should be 1.
303                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}