diff options
Diffstat (limited to 'third_party/rust/deflate/src/lzvalue.rs')
-rw-r--r-- | third_party/rust/deflate/src/lzvalue.rs | 121 |
1 files changed, 121 insertions, 0 deletions
diff --git a/third_party/rust/deflate/src/lzvalue.rs b/third_party/rust/deflate/src/lzvalue.rs new file mode 100644 index 0000000000..acbbde8b20 --- /dev/null +++ b/third_party/rust/deflate/src/lzvalue.rs @@ -0,0 +1,121 @@ +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); + } + } + + } +} |