1use core::mem::size_of;
8
9pub trait BitsSource: Copy {
10 fn into_u128(self) -> u128;
11}
12
13macro_rules! impl_bits_source {
14 ($($t:ty),*) => {
15 $(
16 impl BitsSource for $t {
17 #[inline(always)]
18 fn into_u128(self) -> u128 {
19 self as u128
20 }
21 }
22 )*
23 };
24}
25
26impl_bits_source!(u8, u16, u32, u64, u128, usize);
27
28pub trait BitsTarget: Copy {
29 fn from_u128(val: u128) -> Self;
30}
31
32macro_rules! impl_bits_target {
33 ($($t:ty),*) => {
34 $(
35 impl BitsTarget for $t {
36 #[inline(always)]
37 fn from_u128(val: u128) -> Self {
38 val as $t
39 }
40 }
41 )*
42 };
43}
44
45impl_bits_target!(u8, u16, u32, u64, u128, usize);
46
47impl BitsTarget for bool {
48 #[inline(always)]
49 fn from_u128(val: u128) -> Self {
50 val != 0
51 }
52}
53
54#[inline(always)]
56pub fn extract_bits<const HIGH_BIT: usize, const LOW_BIT: usize, R: BitsTarget, S: BitsSource>(
57 input: S,
58) -> R {
59 const {
60 assert!(HIGH_BIT >= LOW_BIT, "High bit must be greater or equal to low bit.");
61 assert!(HIGH_BIT < size_of::<S>() * 8, "Source value ends before high bit");
62 assert!(
63 (HIGH_BIT + 1 - LOW_BIT) <= size_of::<R>() * 8,
64 "Return type is not large enough to hold requested bits."
65 );
66 }
67 let bit_count = HIGH_BIT + 1 - LOW_BIT;
68 let mask = if bit_count == 128 { u128::MAX } else { (1u128 << bit_count) - 1 };
69 R::from_u128((input.into_u128() >> LOW_BIT) & mask)
70}
71
72#[inline(always)]
73pub fn extract_bit<const BIT: usize, R: BitsTarget, S: BitsSource>(input: S) -> R {
74 extract_bits::<BIT, BIT, R, S>(input)
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn test_extract_bits() {
83 let val: u32 = 0xabcd_1234;
84 assert_eq!(extract_bits::<3, 0, u8, _>(val), 0x4);
85 assert_eq!(extract_bits::<7, 4, u8, _>(val), 0x3);
86 assert_eq!(extract_bits::<11, 8, u8, _>(val), 0x2);
87 assert_eq!(extract_bits::<31, 24, u8, _>(val), 0xab);
88 assert!(extract_bit::<2, bool, _>(val));
89 assert!(!extract_bit::<0, bool, _>(val));
90 }
91}