extern crate alloc;
use alloc::vec::Vec;
use crate::error::Error;
pub(crate) const WINDOW_SIZE: usize = 0x10000;
pub(crate) fn emit_literal(out: &mut Vec<u8>, byte: u8) {
out.push(byte);
}
pub(crate) fn emit_match(out: &mut Vec<u8>, distance: usize, length: usize) -> Result<(), Error> {
if distance == 0 || distance > WINDOW_SIZE || distance > out.len() {
return Err(Error::InvalidDistance);
}
for src in (out.len() - distance..).take(length) {
let b = out[src];
out.push(b);
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;
#[test]
fn literal_then_match() {
let mut out = vec![];
for &b in b"hello" {
emit_literal(&mut out, b);
}
emit_match(&mut out, 5, 5).unwrap();
assert_eq!(&out, b"hellohello");
}
#[test]
fn overlap_run() {
let mut out = vec![];
emit_literal(&mut out, b'A');
emit_match(&mut out, 1, 8).unwrap();
assert_eq!(&out, b"AAAAAAAAA");
}
#[test]
fn overlap_two_byte_period() {
let mut out = vec![];
emit_literal(&mut out, b'A');
emit_literal(&mut out, b'B');
emit_match(&mut out, 2, 6).unwrap();
assert_eq!(&out, b"ABABABAB");
}
#[test]
fn rejects_zero_distance() {
let mut out = vec![1u8];
assert_eq!(emit_match(&mut out, 0, 1), Err(Error::InvalidDistance));
}
#[test]
fn rejects_distance_before_start() {
let mut out = vec![1u8];
assert_eq!(emit_match(&mut out, 2, 1), Err(Error::InvalidDistance));
}
#[test]
fn rejects_distance_over_window() {
let mut out = vec![0u8; WINDOW_SIZE + 10];
assert_eq!(
emit_match(&mut out, WINDOW_SIZE + 1, 1),
Err(Error::InvalidDistance)
);
}
}