use super::{CompressionError, Compressor};
const ESCAPE_LITERAL: u8 = 0x80;
pub struct DeltaPulse;
impl Compressor for DeltaPulse {
fn name(&self) -> &'static str {
"delta-pulse"
}
fn compress(&self, input: &[u8]) -> Vec<u8> {
if input.is_empty() {
return Vec::new();
}
let mut out = Vec::with_capacity(input.len());
out.push(input[0]);
let mut prev = input[0];
for ¤t in &input[1..] {
let delta = current as i16 - prev as i16;
if (-127..=127).contains(&delta) && delta != -128 {
out.push((delta as i8) as u8);
} else {
out.push(ESCAPE_LITERAL);
out.push(current);
}
prev = current;
}
out
}
fn decompress(&self, input: &[u8]) -> Result<Vec<u8>, CompressionError> {
if input.is_empty() {
return Ok(Vec::new());
}
let mut out = Vec::with_capacity(input.len());
out.push(input[0]);
let mut prev = input[0];
let mut i = 1usize;
while i < input.len() {
let token = input[i];
i += 1;
if token == ESCAPE_LITERAL {
if i >= input.len() {
return Err(CompressionError::CorruptStream(
"delta-pulse escape token missing literal byte",
));
}
let literal = input[i];
i += 1;
out.push(literal);
prev = literal;
continue;
}
let delta = (token as i8) as i16;
let next = prev as i16 + delta;
if !(0..=255).contains(&next) {
return Err(CompressionError::ValueOverflow);
}
let value = next as u8;
out.push(value);
prev = value;
}
Ok(out)
}
}