kdmp_parser/
bits.rs

1// Axel '0vercl0k' Souchet - January 21 2024
2//! This defines and implements the [`Bits`] trait which allows user to extract
3//! bit / range of bits off regular integer.
4//!
5//! //! # Examples
6//!
7//! ```
8//! # use kdmp_parser::Bits;
9//! let v = 0xAB_CD_EF_01_23_45_67_89u64;
10//! assert_eq!(v.bits(0..=63), v);
11//! assert_eq!(v.bits(0..=55), 0xCD_EF_01_23_45_67_89);
12//! ```
13use std::mem;
14use std::ops::RangeInclusive;
15
16/// Utility trait to make it easier to extract ranges of bits.
17pub trait Bits: Sized {
18    /// Get a range of bits.
19    fn bits(&self, r: RangeInclusive<usize>) -> Self;
20
21    /// Get a bit.
22    fn bit(&self, n: usize) -> Self {
23        self.bits(n..=n)
24    }
25}
26
27impl<T> Bits for T
28where
29    T: Into<u128> + Copy + TryFrom<u128>,
30    <T as TryFrom<u128>>::Error: std::fmt::Debug,
31{
32    fn bits(&self, r: RangeInclusive<usize>) -> Self {
33        let (start, end) = r.into_inner();
34        let capacity = mem::size_of_val(self) * 8;
35        assert!(start <= end, "the range should have a start <= end");
36        assert!(
37            end < capacity,
38            "the end ({end}) of the range can't exceed the bits capacity ({capacity}) of Self"
39        );
40        let value = (*self).into();
41        let base = value >> start;
42        let n = end - start + 1;
43
44        let mask = if n == capacity {
45            // This prevents to overflow a u128 when doing `(1 << 128) - 1`
46            !0
47        } else {
48            (1 << n) - 1
49        };
50
51        // This cannot fail as we are zero extending `Self` into a `u128` and then the
52        // `mask` cannot index outside the bit capacity of `Self`.
53        T::try_from(base & mask).unwrap()
54    }
55}
56
57#[cfg(test)]
58mod tests {
59    use super::Bits;
60
61    #[test]
62    fn bits64() {
63        let v = 0xAB_CD_EF_01_23_45_67_89u64;
64        assert_eq!(v.bits(0..=63), v);
65        assert_eq!(v.bits(0..=55), 0xCD_EF_01_23_45_67_89);
66        assert_eq!(v.bits(0..=47), 0xEF_01_23_45_67_89);
67        assert_eq!(v.bits(0..=39), 0x01_23_45_67_89);
68        assert_eq!(v.bits(0..=31), 0x23_45_67_89);
69        assert_eq!(v.bits(0..=23), 0x45_67_89);
70        assert_eq!(v.bits(0..=15), 0x67_89);
71        assert_eq!(v.bits(0..=7), 0x89);
72        assert_eq!(v.bits(0..=3), 0x9);
73
74        assert_eq!(v.bits(0..=7), 0x89);
75        assert_eq!(v.bits(8..=15), 0x67);
76        assert_eq!(v.bits(16..=23), 0x45);
77        assert_eq!(v.bits(24..=31), 0x23);
78        assert_eq!(v.bits(32..=39), 0x01);
79        assert_eq!(v.bits(40..=47), 0xEF);
80        assert_eq!(v.bits(48..=55), 0xCD);
81        assert_eq!(v.bits(56..=63), 0xAB);
82        assert_eq!(v.bit(0), 1);
83    }
84
85    #[test]
86    fn bits128() {
87        let v = 0xAB_CD_EF_01_23_45_67_89u128;
88        assert_eq!(v.bits(0..=125), v);
89        assert_eq!(v.bits(0..=55), 0xCD_EF_01_23_45_67_89);
90        assert_eq!(v.bits(0..=47), 0xEF_01_23_45_67_89);
91        assert_eq!(v.bits(0..=39), 0x01_23_45_67_89);
92        assert_eq!(v.bits(0..=31), 0x23_45_67_89);
93        assert_eq!(v.bits(0..=23), 0x45_67_89);
94        assert_eq!(v.bits(0..=15), 0x67_89);
95        assert_eq!(v.bits(0..=7), 0x89);
96        assert_eq!(v.bits(0..=3), 0x9);
97
98        assert_eq!(v.bits(0..=7), 0x89);
99        assert_eq!(v.bits(8..=15), 0x67);
100        assert_eq!(v.bits(16..=23), 0x45);
101        assert_eq!(v.bits(24..=31), 0x23);
102        assert_eq!(v.bits(32..=39), 0x01);
103        assert_eq!(v.bits(40..=47), 0xEF);
104        assert_eq!(v.bits(48..=55), 0xCD);
105        assert_eq!(v.bits(56..=63), 0xAB);
106    }
107
108    #[test]
109    #[allow(clippy::reversed_empty_ranges)]
110    fn invalid_ranges() {
111        assert!(std::panic::catch_unwind(|| 1u64.bits(10..=0)).is_err());
112        assert!(std::panic::catch_unwind(|| 1u128.bits(0..=128)).is_err());
113        assert!(std::panic::catch_unwind(|| 1u64.bits(0..=64)).is_err());
114    }
115}