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