use crate::core::layout::BitRange;
pub trait FromUnalignedRead {
fn from_unaligned_read(v: u128) -> Self;
}
macro_rules! impl_from_u128 {
($($t:ty),*) => {
$(
impl FromUnalignedRead for $t {
#[inline(always)]
fn from_unaligned_read(v: u128) -> Self {
v as $t
}
}
)*
};
}
impl_from_u128!(u8, u16, u32, u64, u128);
#[inline(always)]
pub unsafe fn unchecked_bit_range_be_read<T>(buf: &[u8], range: BitRange) -> T
where
T: FromUnalignedRead,
{
const LANE_BITS: usize = 128;
const LANE_BYTES: usize = LANE_BITS / 8;
let bit_count = range.size_bits();
let bit_range = range.bit_range();
let byte_count = range.size_bytes();
let byte_range = range.containing_byte_range();
debug_assert!(
range.size_bytes() <= LANE_BYTES,
"BitRange too large for write"
);
debug_assert!(byte_range.end <= buf.len(), "write exceeds buffer");
let mut lane = [0u8; 16];
unsafe {
core::ptr::copy_nonoverlapping(
buf.get_unchecked(byte_range).as_ptr(),
lane[LANE_BYTES - byte_count..].as_mut_ptr(),
byte_count,
);
};
let lane_val = u128::from_be_bytes(lane);
let next_full_byte = bit_range.end.div_ceil(8) * 8;
let right_shift = next_full_byte - bit_range.end;
let aligned_val = lane_val >> right_shift;
let value_mask = (1u128 << bit_count) - 1;
let cleaned_val = aligned_val & value_mask;
T::from_unaligned_read(cleaned_val)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_read_aligned_u8() {
let buf = [0b10101010u8, 0];
let val: u8 = unsafe { unchecked_bit_range_be_read(&buf, BitRange::new(0, 8)) };
println!("val = {:08b}", val);
assert_eq!(val, 0b10101010);
}
#[test]
fn should_read_aligned_u16() {
let buf = [0b10101010, 0b01010101];
let val: u16 = unsafe { unchecked_bit_range_be_read(&buf, BitRange::new(0, 16)) };
println!("val = {:016b}", val);
assert_eq!(val, 0b1010101001010101);
}
#[test]
fn should_read_unaligned_single_byte() {
let buf = [0b00011100];
let val: u8 = unsafe { unchecked_bit_range_be_read(&buf, BitRange::new(3, 3)) };
println!("val = {:03b}", val);
assert_eq!(val, 0b111);
}
#[test]
fn should_read_cross_byte() {
let buf = [0b00000011, 0b01000000, 0];
let val: u16 = unsafe { unchecked_bit_range_be_read(&buf, BitRange::new(6, 4)) };
println!("val = {:010b}", val);
assert_eq!(val, 0b1101);
}
#[test]
fn should_read_large_cross_byte() {
let buf = [0b00000011, 0b01111111, 0b11111111, 0b01000000, 0];
let val: u32 = unsafe { unchecked_bit_range_be_read(&buf, BitRange::new(6, 20)) };
println!("val = {:020b}", val);
assert_eq!(val, 0b1101_1111_1111_1111_1101);
}
#[test]
fn should_read_bits_at_long_offset() {
let mut buf = [0u8; 20];
buf[10] = 0b00111100;
let range = BitRange::new(10 * 8 + 2, 4); let val: u8 = unsafe { unchecked_bit_range_be_read(&buf, range) };
println!("val = {:04b}", val);
assert_eq!(val, 0b1111);
}
}