deflate/
lzvalue.rs
1#[cfg(test)]
2use crate::huffman_table::MAX_MATCH;
3use crate::huffman_table::{MAX_DISTANCE, MIN_MATCH};
4
5#[derive(Copy, Clone, Eq, PartialEq, Debug)]
6pub struct StoredLength {
7 length: u8,
8}
9
10impl StoredLength {
11 #[cfg(test)]
12 pub fn from_actual_length(length: u16) -> StoredLength {
13 assert!(length <= MAX_MATCH && length >= MIN_MATCH);
14 StoredLength {
15 length: (length - MIN_MATCH) as u8,
16 }
17 }
18
19 pub const fn new(stored_length: u8) -> StoredLength {
20 StoredLength {
21 length: stored_length,
22 }
23 }
24
25 pub const fn stored_length(&self) -> u8 {
26 self.length
27 }
28
29 #[cfg(test)]
30 pub fn actual_length(&self) -> u16 {
31 u16::from(self.length) + MIN_MATCH
32 }
33}
34
35#[derive(Copy, Clone, Eq, PartialEq, Debug)]
36pub enum LZType {
37 Literal(u8),
38 StoredLengthDistance(StoredLength, u16),
39}
40
41#[derive(Copy, Clone, Eq, PartialEq, Debug)]
42pub struct LZValue {
43 litlen: u8,
44 distance: u16,
45}
46
47impl LZValue {
48 #[inline]
49 pub const fn literal(value: u8) -> LZValue {
50 LZValue {
51 litlen: value,
52 distance: 0,
53 }
54 }
55
56 #[inline]
58 pub fn length_distance(length: u16, distance: u16) -> LZValue {
59 debug_assert!(distance > 0 && distance <= MAX_DISTANCE);
61 let stored_length = (length - MIN_MATCH) as u8;
62 LZValue {
63 litlen: stored_length,
64 distance,
65 }
66 }
67
68 #[inline]
69 pub fn value(&self) -> LZType {
70 if self.distance != 0 {
71 LZType::StoredLengthDistance(StoredLength::new(self.litlen), self.distance)
72 } else {
73 LZType::Literal(self.litlen)
74 }
75 }
76}
77
78#[cfg(test)]
79pub fn lit(l: u8) -> LZValue {
80 LZValue::literal(l)
81}
82
83#[cfg(test)]
84pub fn ld(l: u16, d: u16) -> LZValue {
85 LZValue::length_distance(l, d)
86}
87
88#[cfg(test)]
89mod test {
90 use super::*;
91 use crate::huffman_table::{MAX_DISTANCE, MAX_MATCH, MIN_DISTANCE, MIN_MATCH};
92 #[test]
93 fn lzvalue() {
94 for i in 0..255 as usize + 1 {
95 let v = LZValue::literal(i as u8);
96 if let LZType::Literal(n) = v.value() {
97 assert_eq!(n as usize, i);
98 } else {
99 panic!();
100 }
101 }
102
103 for i in MIN_MATCH..MAX_MATCH + 1 {
104 let v = LZValue::length_distance(i, 5);
105 if let LZType::StoredLengthDistance(l, _) = v.value() {
106 assert_eq!(l.actual_length(), i);
107 } else {
108 panic!();
109 }
110 }
111
112 for i in MIN_DISTANCE..MAX_DISTANCE + 1 {
113 let v = LZValue::length_distance(5, i);
114
115 if let LZType::StoredLengthDistance(_, d) = v.value() {
116 assert_eq!(d, i);
117 } else {
118 panic!("Failed to get distance {}", i);
119 }
120 }
121 }
122}