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