paracletics-hypercube 0.1.0

General-purpose paracletic hyper cube compression toolkit.
Documentation
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)
    }
}