| use huffman_table::{MAX_DISTANCE, MIN_MATCH}; |
| #[cfg(test)] |
| use huffman_table::MAX_MATCH; |
| |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| pub struct StoredLength { |
| length: u8, |
| } |
| |
| impl StoredLength { |
| #[cfg(test)] |
| pub fn from_actual_length(length: u16) -> StoredLength { |
| assert!(length <= MAX_MATCH && length >= MIN_MATCH); |
| StoredLength { |
| length: (length - MIN_MATCH) as u8, |
| } |
| } |
| |
| pub fn new(stored_length: u8) -> StoredLength { |
| StoredLength { |
| length: stored_length, |
| } |
| } |
| |
| pub fn stored_length(&self) -> u8 { |
| self.length |
| } |
| |
| #[cfg(test)] |
| pub fn actual_length(&self) -> u16 { |
| u16::from(self.length) + MIN_MATCH |
| } |
| } |
| |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| pub enum LZType { |
| Literal(u8), |
| StoredLengthDistance(StoredLength, u16), |
| } |
| |
| #[derive(Copy, Clone, Eq, PartialEq, Debug)] |
| pub struct LZValue { |
| litlen: u8, |
| distance: u16, |
| } |
| |
| impl LZValue { |
| #[inline] |
| pub fn literal(value: u8) -> LZValue { |
| LZValue { |
| litlen: value, |
| distance: 0, |
| } |
| } |
| |
| #[inline] |
| pub fn length_distance(length: u16, distance: u16) -> LZValue { |
| debug_assert!(distance > 0 && distance <= MAX_DISTANCE); |
| let stored_length = (length - MIN_MATCH) as u8; |
| LZValue { |
| litlen: stored_length, |
| distance: distance, |
| } |
| } |
| |
| #[inline] |
| pub fn value(&self) -> LZType { |
| if self.distance != 0 { |
| LZType::StoredLengthDistance(StoredLength::new(self.litlen), self.distance) |
| } else { |
| LZType::Literal(self.litlen) |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| pub fn lit(l: u8) -> LZValue { |
| LZValue::literal(l) |
| } |
| |
| #[cfg(test)] |
| pub fn ld(l: u16, d: u16) -> LZValue { |
| LZValue::length_distance(l, d) |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| use huffman_table::{MIN_MATCH, MIN_DISTANCE, MAX_MATCH, MAX_DISTANCE}; |
| #[test] |
| fn lzvalue() { |
| for i in 0..255 as usize + 1 { |
| let v = LZValue::literal(i as u8); |
| if let LZType::Literal(n) = v.value() { |
| assert_eq!(n as usize, i); |
| } else { |
| panic!(); |
| } |
| } |
| |
| for i in MIN_MATCH..MAX_MATCH + 1 { |
| let v = LZValue::length_distance(i, 5); |
| if let LZType::StoredLengthDistance(l, _) = v.value() { |
| assert_eq!(l.actual_length(), i); |
| } else { |
| panic!(); |
| } |
| } |
| |
| for i in MIN_DISTANCE..MAX_DISTANCE + 1 { |
| let v = LZValue::length_distance(5, i); |
| |
| if let LZType::StoredLengthDistance(_, d) = v.value() { |
| assert_eq!(d, i); |
| } else { |
| panic!("Failed to get distance {}", i); |
| } |
| } |
| |
| } |
| } |