use crate::{
private::{PopBits, PopBuffer, PushBits, PushBuffer},
Specifier,
};
#[inline]
fn push_buffer<T>() -> PushBuffer<<T as Specifier>::Bytes>
where
T: Specifier,
PushBuffer<T::Bytes>: Default,
{
<PushBuffer<<T as Specifier>::Bytes> as Default>::default()
}
#[doc(hidden)]
#[inline]
#[must_use]
pub fn read_specifier<T>(bytes: &[u8], offset: usize) -> <T as Specifier>::Bytes
where
T: Specifier,
PushBuffer<T::Bytes>: Default + PushBits,
{
let end = offset + <T as Specifier>::BITS;
let ls_byte = offset / 8; let ms_byte = (end - 1) / 8;
#[allow(clippy::cast_possible_truncation)]
let lsb_offset = (offset % 8) as u32; #[allow(clippy::cast_possible_truncation)]
let msb_offset = (end % 8) as u32; let msb_offset = if msb_offset == 0 { 8 } else { msb_offset };
let mut buffer = push_buffer::<T>();
if lsb_offset == 0 && msb_offset == 8 {
for byte in bytes[ls_byte..=ms_byte].iter().rev() {
buffer.push_bits(8, *byte);
}
} else {
if ls_byte != ms_byte {
buffer.push_bits(msb_offset, bytes[ms_byte]);
}
if ms_byte - ls_byte >= 2 {
for byte in bytes[(ls_byte + 1)..ms_byte].iter().rev() {
buffer.push_bits(8, *byte);
}
}
if ls_byte == ms_byte {
buffer.push_bits(
u32::try_from(<T as Specifier>::BITS).unwrap(),
bytes[ls_byte] >> lsb_offset,
);
} else {
buffer.push_bits(8 - lsb_offset, bytes[ls_byte] >> lsb_offset);
}
}
buffer.into_bytes()
}
#[doc(hidden)]
#[inline]
pub fn write_specifier<T>(bytes: &mut [u8], offset: usize, new_val: <T as Specifier>::Bytes)
where
T: Specifier,
PopBuffer<T::Bytes>: PopBits,
{
let end = offset + <T as Specifier>::BITS;
let ls_byte = offset / 8; let ms_byte = (end - 1) / 8;
#[allow(clippy::cast_possible_truncation)]
let lsb_offset = (offset % 8) as u32; #[allow(clippy::cast_possible_truncation)]
let msb_offset = (end % 8) as u32; let msb_offset = if msb_offset == 0 { 8 } else { msb_offset };
let mut buffer = <PopBuffer<T::Bytes>>::from_bytes(new_val);
if lsb_offset == 0 && msb_offset == 8 {
for byte in &mut bytes[ls_byte..=ms_byte] {
*byte = buffer.pop_bits(8);
}
} else {
let stays_same = bytes[ls_byte]
& (if ls_byte == ms_byte && msb_offset != 8 {
!((1 << msb_offset) - 1)
} else {
0u8
} | ((1 << lsb_offset) - 1));
let overwrite = buffer.pop_bits(8 - lsb_offset);
bytes[ls_byte] = stays_same | (overwrite << lsb_offset);
if ms_byte - ls_byte >= 2 {
for byte in &mut bytes[(ls_byte + 1)..ms_byte] {
*byte = buffer.pop_bits(8);
}
}
if ls_byte != ms_byte {
if msb_offset == 8 {
bytes[ms_byte] = buffer.pop_bits(msb_offset);
} else {
let stays_same = bytes[ms_byte] & !((1 << msb_offset) - 1);
let overwrite = buffer.pop_bits(msb_offset);
bytes[ms_byte] = stays_same | overwrite;
}
}
}
}