use super::{CompressionError, Compressor};
pub struct RunLength;
impl Compressor for RunLength {
fn name(&self) -> &'static str {
"run-length"
}
fn compress(&self, input: &[u8]) -> Vec<u8> {
if input.is_empty() {
return Vec::new();
}
let mut out = Vec::with_capacity((input.len() / 2).max(2));
let mut i = 0usize;
while i < input.len() {
let symbol = input[i];
let mut run = 1usize;
while i + run < input.len() && input[i + run] == symbol && run < u8::MAX as usize {
run += 1;
}
out.push(run as u8);
out.push(symbol);
i += run;
}
out
}
fn decompress(&self, input: &[u8]) -> Result<Vec<u8>, CompressionError> {
if input.is_empty() {
return Ok(Vec::new());
}
if input.len() % 2 != 0 {
return Err(CompressionError::CorruptStream(
"run-length stream had odd byte count",
));
}
let mut out = Vec::new();
let mut i = 0usize;
while i < input.len() {
let run = input[i];
let symbol = input[i + 1];
if run == 0 {
return Err(CompressionError::CorruptStream("run length cannot be zero"));
}
out.extend(std::iter::repeat_n(symbol, run as usize));
i += 2;
}
Ok(out)
}
}