pub fn control_len(count: usize) -> usize {
count.div_ceil(4)
}
pub fn encode(values: &[u32], out: &mut Vec<u8>) {
let control_start = out.len();
out.resize(control_start.saturating_add(control_len(values.len())), 0);
for (index, &value) in values.iter().enumerate() {
let width = byte_width(value);
let code = u8::try_from(width.saturating_sub(1)).unwrap_or(0);
let slot = control_start.saturating_add(index / 4);
let shift = u32::try_from((index % 4).saturating_mul(2)).unwrap_or(0);
if let Some(byte) = out.get_mut(slot) {
*byte |= code.wrapping_shl(shift);
}
if let Some(bytes) = value.to_le_bytes().get(..width) {
out.extend_from_slice(bytes);
}
}
}
pub fn encoded_len(values: &[u32]) -> usize {
values
.iter()
.fold(control_len(values.len()), |total, &value| {
total.saturating_add(byte_width(value))
})
}
fn byte_width(value: u32) -> usize {
match value {
0..=0xFF => 1,
0x100..=0xFFFF => 2,
0x1_0000..=0x00FF_FFFF => 3,
0x0100_0000..=0xFFFF_FFFF => 4,
}
}
#[derive(Debug, Clone)]
pub struct Reader<'a> {
control: &'a [u8],
data: &'a [u8],
index: usize,
offset: usize,
}
impl<'a> Reader<'a> {
pub fn new(section: &'a [u8], count: usize) -> Option<Self> {
let (control, data) = section.split_at_checked(control_len(count))?;
Some(Self {
control,
data,
index: 0,
offset: 0,
})
}
}
impl Iterator for Reader<'_> {
type Item = u32;
fn next(&mut self) -> Option<u32> {
let slot = self.control.get(self.index / 4)?;
let shift = u32::try_from((self.index % 4).saturating_mul(2)).unwrap_or(0);
let code = usize::try_from(u32::from(*slot).wrapping_shr(shift) & 0b11).ok()?;
let width = code.saturating_add(1);
let end = self.offset.checked_add(width)?;
let bytes = self.data.get(self.offset..end)?;
let mut buffer = [0_u8; 4];
buffer.get_mut(..width)?.copy_from_slice(bytes);
self.offset = end;
self.index = self.index.checked_add(1)?;
Some(u32::from_le_bytes(buffer))
}
}
pub fn zigzag(value: i32) -> u32 {
let folded = value.wrapping_shl(1) ^ value.wrapping_shr(31);
u32::from_ne_bytes(folded.to_ne_bytes())
}
pub fn unzigzag(value: u32) -> i32 {
let magnitude = i32::from_ne_bytes(value.wrapping_shr(1).to_ne_bytes());
let sign = i32::from_ne_bytes((value & 1).to_ne_bytes()).wrapping_neg();
magnitude ^ sign
}