1use std::mem;
14use std::ops::RangeInclusive;
15
16pub trait Bits: Sized {
18 fn bits(&self, r: RangeInclusive<usize>) -> Self;
20
21 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 !0
47 } else {
48 (1 << n) - 1
49 };
50
51 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}