use core::ops::{Shl, Shr};
pub trait Key:
Copy + Shl<u8, Output = Self> + Shr<u8, Output = Self> + Sized
{
const BITS: u8;
fn to_u8(self) -> u8;
fn rotate_right(self, n: u32) -> Self;
}
impl Key for u32 {
const BITS: u8 = 32;
#[inline(always)]
fn to_u8(self) -> u8 {
self as u8
}
#[inline(always)]
fn rotate_right(self, n: u32) -> Self {
self.rotate_right(n)
}
}
impl Key for u128 {
const BITS: u8 = 128;
#[inline(always)]
fn to_u8(self) -> u8 {
self as u8
}
#[inline(always)]
fn rotate_right(self, n: u32) -> Self {
self.rotate_right(n)
}
}
#[inline(always)]
pub(crate) fn extract_bits<K>(key: K, offset: u8, len: u8) -> u8
where
K: Key,
{
(key.rotate_right((K::BITS - offset).wrapping_sub(len) as u32)).to_u8()
& ((1u16 << len) - 1) as u8
}
#[inline(always)]
pub(crate) fn extract_bits_saturated<K>(key: K, offset: u8, len: u8) -> u8
where
K: Key,
{
let remaining = u8::saturating_sub(K::BITS - offset, len);
if remaining + offset == K::BITS {
return 0;
}
(key << offset >> (remaining + offset)).to_u8()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_extraction() {
let key: u32 = 0b11111111_01010101_11110000_11001100;
assert_eq!(extract_bits(key, 0, 8), 0b11111111);
assert_eq!(extract_bits(key, 8, 8), 0b01010101);
assert_eq!(extract_bits(key, 16, 8), 0b11110000);
assert_eq!(extract_bits(key, 24, 8), 0b11001100);
}
#[test]
fn test_saturated_extraction() {
let key: u32 = 0b000000_000000_000000_000000_000000_01;
assert_eq!(extract_bits_saturated(key, 30, 6), 1);
let key: u32 = 0b000001_000001_000001_000001_000001_01;
assert_eq!(extract_bits_saturated(key, 30, 6), 1);
}
#[test]
fn test_msb_alignement() {
let key: u32 = 0b000000_000000_000000_000000_000000_01;
assert_eq!(extract_bits(key, 30, 6), 0b0001_0000);
let key: u32 = 0b000001_000001_000001_000001_000001_01;
assert_eq!(extract_bits(key, 30, 6), 0b0001_0000);
assert_eq!(extract_bits(key, 0, 6), 0b0000_0001);
}
}