use generic_compression::lz::{
lz77::{LZ77entry, LZ77tuple},
lz78::{LZ78entry, LZ78tuple},
};
use num_traits::ToBytes;
use std::{
error,
io::{self, Write},
};
const U8_MAX: usize = u8::MAX as usize;
const U16_MAX: usize = u16::MAX as usize;
const U32_MAX: usize = u32::MAX as usize;
fn min_size(val: usize) -> u8 {
if val <= U8_MAX {
1
} else if val <= U16_MAX {
2
} else if val <= U32_MAX {
4
} else {
8
}
}
fn serialize_usize<W: Write>(value: usize, state: &mut W, num_bytes: u8) -> io::Result<()> {
match num_bytes {
1 => {
state.write_all(&[value as u8])?;
}
2 => {
state.write_all(&(value as u16).to_le_bytes())?;
}
4 => {
state.write_all(&(value as u32).to_le_bytes())?;
}
8 => {
state.write_all(&value.to_le_bytes())?;
}
_ => unreachable!(),
}
Ok(())
}
pub fn serialize_lz77<T: ToBytes, W: Write>(
value: Vec<LZ77entry<T>>,
window_size: usize,
lookahead_buffer_size: usize,
state: &mut W,
) -> Result<(), Box<dyn error::Error>> {
serialize_usize(value.len(), state, 8)?;
let window_size_bytes = min_size(window_size);
state.write(&[window_size_bytes])?;
let lookahead_buffer_size_bytes = min_size(lookahead_buffer_size);
state.write(&[lookahead_buffer_size_bytes])?;
for entry in value {
let tp: LZ77tuple<T> = entry.into();
serialize_usize(tp.0, state, window_size_bytes)?;
serialize_usize(tp.1, state, lookahead_buffer_size_bytes)?;
let bytes = tp.2.to_le_bytes();
state.write_all(bytes.as_ref())?;
}
Ok(())
}
pub fn serialize_lz78<T: ToBytes, W: Write>(
value: Vec<LZ78entry<T>>,
dictionary_size: usize,
state: &mut W,
) -> Result<(), Box<dyn error::Error>> {
serialize_usize(value.len(), state, 8)?;
let dictionary_size_bytes = min_size(dictionary_size);
state.write(&[dictionary_size_bytes])?;
for entry in value {
let tp: LZ78tuple<T> = entry.into();
if let Some(idx) = tp.0 {
serialize_usize(idx + 1, state, dictionary_size_bytes)?;
} else {
serialize_usize(0, state, dictionary_size_bytes)?; }
let bytes = tp.1.to_le_bytes();
state.write_all(bytes.as_ref())?;
}
Ok(())
}
pub fn serialize_lzw<W: Write>(
value: Vec<usize>,
state: &mut W,
) -> Result<(), Box<dyn error::Error>> {
serialize_usize(value.len(), state, 8)?;
let width = min_size(value.iter().copied().max().unwrap_or(0));
state.write(&[width])?;
for entry in value {
serialize_usize(entry, state, width)?;
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_serialize_usize() {
let mut buffer = Vec::new();
serialize_usize(42, &mut buffer, 1).unwrap();
assert_eq!(buffer, vec![42]);
buffer.clear();
serialize_usize(300, &mut buffer, 2).unwrap();
assert_eq!(buffer, vec![44, 1]);
buffer.clear();
serialize_usize(70000, &mut buffer, 4).unwrap();
assert_eq!(buffer, vec![112, 17, 1, 0]);
buffer.clear();
serialize_usize(7000000000, &mut buffer, 8).unwrap();
assert_eq!(buffer, vec![0, 134, 59, 161, 1, 0, 0, 0]);
}
}