deflate/
lzvalue.rs
1use huffman_table::{MAX_DISTANCE, MIN_MATCH};
2#[cfg(test)]
3use huffman_table::MAX_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 fn new(stored_length: u8) -> StoredLength {
20 StoredLength {
21 length: stored_length,
22 }
23 }
24
25 pub 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 fn literal(value: u8) -> LZValue {
50 LZValue {
51 litlen: value,
52 distance: 0,
53 }
54 }
55
56 #[inline]
57 pub fn length_distance(length: u16, distance: u16) -> LZValue {
58 debug_assert!(distance > 0 && distance <= MAX_DISTANCE);
59 let stored_length = (length - MIN_MATCH) as u8;
60 LZValue {
61 litlen: stored_length,
62 distance: distance,
63 }
64 }
65
66 #[inline]
67 pub fn value(&self) -> LZType {
68 if self.distance != 0 {
69 LZType::StoredLengthDistance(StoredLength::new(self.litlen), self.distance)
70 } else {
71 LZType::Literal(self.litlen)
72 }
73 }
74}
75
76#[cfg(test)]
77pub fn lit(l: u8) -> LZValue {
78 LZValue::literal(l)
79}
80
81#[cfg(test)]
82pub fn ld(l: u16, d: u16) -> LZValue {
83 LZValue::length_distance(l, d)
84}
85
86#[cfg(test)]
87mod test {
88 use super::*;
89 use huffman_table::{MIN_MATCH, MIN_DISTANCE, MAX_MATCH, MAX_DISTANCE};
90 #[test]
91 fn lzvalue() {
92 for i in 0..255 as usize + 1 {
93 let v = LZValue::literal(i as u8);
94 if let LZType::Literal(n) = v.value() {
95 assert_eq!(n as usize, i);
96 } else {
97 panic!();
98 }
99 }
100
101 for i in MIN_MATCH..MAX_MATCH + 1 {
102 let v = LZValue::length_distance(i, 5);
103 if let LZType::StoredLengthDistance(l, _) = v.value() {
104 assert_eq!(l.actual_length(), i);
105 } else {
106 panic!();
107 }
108 }
109
110 for i in MIN_DISTANCE..MAX_DISTANCE + 1 {
111 let v = LZValue::length_distance(5, i);
112
113 if let LZType::StoredLengthDistance(_, d) = v.value() {
114 assert_eq!(d, i);
115 } else {
116 panic!("Failed to get distance {}", i);
117 }
118 }
119
120 }
121}