1 #[cfg(test)]
2 use crate::huffman_table::MAX_MATCH;
3 use crate::huffman_table::{MAX_DISTANCE, MIN_MATCH};
4 
5 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
6 pub struct StoredLength {
7     length: u8,
8 }
9 
10 impl StoredLength {
11     #[cfg(test)]
from_actual_length(length: u16) -> StoredLength12     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 
new(stored_length: u8) -> StoredLength19     pub const fn new(stored_length: u8) -> StoredLength {
20         StoredLength {
21             length: stored_length,
22         }
23     }
24 
stored_length(&self) -> u825     pub const fn stored_length(&self) -> u8 {
26         self.length
27     }
28 
29     #[cfg(test)]
actual_length(&self) -> u1630     pub fn actual_length(&self) -> u16 {
31         u16::from(self.length) + MIN_MATCH
32     }
33 }
34 
35 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
36 pub enum LZType {
37     Literal(u8),
38     StoredLengthDistance(StoredLength, u16),
39 }
40 
41 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
42 pub struct LZValue {
43     litlen: u8,
44     distance: u16,
45 }
46 
47 impl LZValue {
48     #[inline]
literal(value: u8) -> LZValue49     pub const fn literal(value: u8) -> LZValue {
50         LZValue {
51             litlen: value,
52             distance: 0,
53         }
54     }
55 
56     /// Create length-distance pair.
57     #[inline]
length_distance(length: u16, distance: u16) -> LZValue58     pub fn length_distance(length: u16, distance: u16) -> LZValue {
59         // TODO: Enforce min/max without too much perf penalty.
60         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]
value(&self) -> LZType69     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)]
lit(l: u8) -> LZValue79 pub fn lit(l: u8) -> LZValue {
80     LZValue::literal(l)
81 }
82 
83 #[cfg(test)]
ld(l: u16, d: u16) -> LZValue84 pub fn ld(l: u16, d: u16) -> LZValue {
85     LZValue::length_distance(l, d)
86 }
87 
88 #[cfg(test)]
89 mod test {
90     use super::*;
91     use crate::huffman_table::{MAX_DISTANCE, MAX_MATCH, MIN_DISTANCE, MIN_MATCH};
92     #[test]
lzvalue()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 }
123