use std::io::{Read, Write};
pub struct Compressor<R> {
reader: R,
}
impl<R: Read> Compressor<R> {
pub fn new(reader: R) -> Self {
Self { reader }
}
pub fn compress(&mut self, mut output: impl Write) -> std::io::Result<()> {
let mut buf = [0u8; 2];
let mut cb_count: usize = 1;
let mut nb = [0u8; 1];
self.reader.read_exact(&mut buf)?;
let mut has_finished = false;
loop {
if buf[0] == buf[1] && !has_finished && cb_count <= usize::MAX {
cb_count += 1;
} else {
writeln!(output, "{}x{cb_count}", buf[0])?;
cb_count = 1;
if has_finished {
break;
}
}
if self.reader.read_exact(&mut nb).is_ok() {
buf[0] = buf[1];
buf[1] = nb[0];
} else {
has_finished = true;
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::compressor::Compressor;
#[test]
fn test_compress() {
const COMPRESSED_CHAR: char = 'a';
let compress = {
let char_string = COMPRESSED_CHAR.to_string();
char_string.repeat(100)
};
let compress_bytes = compress.as_bytes();
let mut compressor = Compressor::new(compress_bytes);
let mut compressed = Vec::new();
compressor.compress(&mut compressed).unwrap();
assert_eq!(
compressed,
format!("{}x100\n", COMPRESSED_CHAR as u8).as_bytes()
);
}
#[test]
fn test_complex() {
let compress = "aaxbbb".repeat(10);
let compress_bytes = compress.as_bytes();
let mut compressor = Compressor::new(compress_bytes);
let mut compressed = Vec::new();
compressor.compress(&mut compressed).unwrap();
assert_eq!(
compressed,
format!("{}x2\n{}x1\n{}x3\n", 'a' as u8, 'x' as u8, 'b' as u8)
.repeat(10)
.as_bytes()
);
}
}