#![allow(dead_code)]
extern crate alloc;
use alloc::vec::Vec;
pub(crate) fn rle1_forward(input: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(input.len());
let mut i = 0;
while i < input.len() {
let b = input[i];
let mut run = 1usize;
while i + run < input.len() && input[i + run] == b && run < 255 {
run += 1;
}
if run < 4 {
for _ in 0..run {
out.push(b);
}
} else {
out.push(b);
out.push(b);
out.push(b);
out.push(b);
out.push((run - 4) as u8);
}
i += run;
}
out
}
pub(crate) fn rle1_inverse(input: &[u8]) -> Vec<u8> {
let mut out = Vec::with_capacity(input.len());
let mut i = 0;
while i < input.len() {
let b = input[i];
out.push(b);
i += 1;
if i >= input.len() || input[i] != b {
continue;
}
out.push(b);
i += 1;
if i >= input.len() || input[i] != b {
continue;
}
out.push(b);
i += 1;
if i >= input.len() || input[i] != b {
continue;
}
out.push(b);
i += 1;
if i < input.len() {
let extra = input[i] as usize;
i += 1;
for _ in 0..extra {
out.push(b);
}
}
}
out
}
pub(crate) fn rle2_forward(mtf_indices: &[u8], alphabet_size: usize) -> Vec<u16> {
let _ = alphabet_size;
let mut out: Vec<u16> = Vec::with_capacity(mtf_indices.len());
let mut run: u32 = 0;
for &i in mtf_indices {
if i == 0 {
run += 1;
} else {
emit_run(&mut out, run);
run = 0;
out.push((i as u16) + 1);
}
}
emit_run(&mut out, run);
out
}
fn emit_run(out: &mut Vec<u16>, mut run: u32) {
if run == 0 {
return;
}
loop {
if run % 2 == 1 {
out.push(0); run = (run - 1) / 2;
} else {
out.push(1); run = (run - 2) / 2;
}
if run == 0 {
break;
}
}
}
pub(crate) fn rle2_inverse(symbols: &[u16]) -> Vec<u8> {
let mut out = Vec::with_capacity(symbols.len());
let mut i = 0;
while i < symbols.len() {
let s = symbols[i];
if s <= 1 {
let mut run: u32 = 0;
let mut weight: u32 = 1;
while i < symbols.len() && symbols[i] <= 1 {
let contrib = if symbols[i] == 0 { 1 } else { 2 };
run = run.saturating_add(contrib * weight);
weight = weight.saturating_mul(2);
i += 1;
}
out.extend(core::iter::repeat_n(0u8, run as usize));
} else {
out.push((s - 1) as u8);
i += 1;
}
}
out
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn rle1_short_runs_passthrough() {
let v = b"abcabc";
assert_eq!(rle1_forward(v), v);
assert_eq!(rle1_inverse(&rle1_forward(v)), v);
}
#[test]
fn rle1_run_of_four_emits_extra() {
let v = b"aaaa";
let r = rle1_forward(v);
assert_eq!(r, vec![b'a', b'a', b'a', b'a', 0]);
assert_eq!(rle1_inverse(&r), v);
}
#[test]
fn rle1_run_of_seven() {
let v = b"aaaaaaa";
let r = rle1_forward(v);
assert_eq!(r, vec![b'a', b'a', b'a', b'a', 3]);
assert_eq!(rle1_inverse(&r), v);
}
#[test]
fn rle1_long_run_capped() {
let v = vec![b'a'; 256];
let r = rle1_forward(&v);
assert_eq!(r.len(), 6);
assert_eq!(r[..5], [b'a', b'a', b'a', b'a', 251]);
assert_eq!(r[5], b'a');
assert_eq!(rle1_inverse(&r), v);
}
#[test]
fn rle2_round_trip() {
let mtf = vec![0u8, 0, 0, 1, 2, 0, 0, 0, 0, 5, 0];
let alphabet_size = 6;
let sym = rle2_forward(&mtf, alphabet_size);
let inv = rle2_inverse(&sym);
assert_eq!(inv, mtf);
}
#[test]
fn rle2_empty() {
let sym = rle2_forward(&[], 4);
assert!(sym.is_empty());
assert!(rle2_inverse(&sym).is_empty());
}
}