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}