deflate/
input_buffer.rs
1use std::cmp;
2
3use crate::chained_hash_table::WINDOW_SIZE;
4
5const MAX_MATCH: usize = crate::huffman_table::MAX_MATCH as usize;
6
7pub const BUFFER_SIZE: usize = (WINDOW_SIZE * 2) + MAX_MATCH;
9
10pub struct InputBuffer {
11 buffer: Vec<u8>,
12}
13
14impl InputBuffer {
15 #[cfg(test)]
16 pub fn new<'a>(data: &'a [u8]) -> (InputBuffer, Option<&[u8]>) {
17 let mut b = InputBuffer::empty();
18 let rem = b.add_data(data);
19 (b, rem)
20 }
21
22 pub fn empty() -> InputBuffer {
23 InputBuffer {
24 buffer: Vec::with_capacity(BUFFER_SIZE),
25 }
26 }
27
28 pub fn add_data<'a>(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
32 debug_assert!(self.current_end() <= BUFFER_SIZE);
33 if self.current_end() + data.len() > BUFFER_SIZE {
34 let consumed = {
36 let space_left = BUFFER_SIZE - self.buffer.len();
37 self.buffer.extend_from_slice(&data[..space_left]);
38 space_left
39 };
40 Some(&data[consumed..])
41 } else {
42 self.buffer.extend_from_slice(data);
44 None
45 }
46 }
47
48 pub fn current_end(&self) -> usize {
50 self.buffer.len()
51 }
52
53 pub fn slide<'a>(&mut self, data: &'a [u8]) -> Option<&'a [u8]> {
57 assert!(self.buffer.len() > WINDOW_SIZE * 2);
59
60 let (final_len, upper_len, end) = {
62 let (lower, upper) = self.buffer.split_at_mut(WINDOW_SIZE);
64 lower.copy_from_slice(&upper[..WINDOW_SIZE]);
66 let lookahead_len = {
67 let (upper_2, lookahead) = upper.split_at_mut(WINDOW_SIZE);
69 let lookahead_len = lookahead.len();
70 debug_assert!(lookahead_len <= MAX_MATCH);
71 upper_2[..lookahead_len].copy_from_slice(lookahead);
72 lookahead_len
73 };
74
75 let upper_len = upper.len() - lookahead_len;
77 let end = cmp::min(data.len(), upper_len);
78 upper[lookahead_len..lookahead_len + end].copy_from_slice(&data[..end]);
79 (lower.len() + lookahead_len + end, upper_len, end)
81 };
82 self.buffer.truncate(final_len);
84
85 if data.len() > upper_len {
86 Some(&data[end..])
88 } else {
89 None
90 }
91 }
92
93 pub fn get_buffer(&mut self) -> &mut [u8] {
95 &mut self.buffer
96 }
97}
98
99#[cfg(test)]
100mod test {
101 use super::MAX_MATCH;
102 use super::*;
103 use crate::chained_hash_table::WINDOW_SIZE;
104 #[test]
105 pub fn buffer_add_full() {
106 let data = [10u8; BUFFER_SIZE + 10];
107 let (mut buf, extra) = InputBuffer::new(&data[..]);
108 assert!(extra.unwrap() == &[10; 10]);
109 let to_add = [2, 5, 3];
110 let not_added = buf.add_data(&to_add);
111 assert_eq!(not_added.unwrap(), to_add);
112 }
113
114 #[test]
115 pub fn buffer_add_not_full() {
116 let data = [10u8; BUFFER_SIZE - 5];
117 let (mut buf, extra) = InputBuffer::new(&data[..]);
118 assert_eq!(buf.current_end(), data.len());
119 assert_eq!(extra, None);
120 let to_add = [2, 5, 3];
121 {
122 let not_added = buf.add_data(&to_add);
123 assert!(not_added.is_none());
124 }
125 let not_added = buf.add_data(&to_add);
126 assert_eq!(not_added.unwrap()[0], 3);
127 }
128
129 #[test]
130 fn slide() {
131 let data = [10u8; BUFFER_SIZE];
132 let (mut buf, extra) = InputBuffer::new(&data[..]);
133 assert_eq!(extra, None);
134 let to_add = [5; 5];
135 let rem = buf.slide(&to_add);
136 assert!(rem.is_none());
137 {
138 let slice = buf.get_buffer();
139 assert!(slice[..WINDOW_SIZE + MAX_MATCH] == data[WINDOW_SIZE..]);
140 assert_eq!(
141 slice[WINDOW_SIZE + MAX_MATCH..WINDOW_SIZE + MAX_MATCH + 5],
142 to_add
143 );
144 }
145 assert_eq!(buf.current_end(), WINDOW_SIZE + MAX_MATCH + to_add.len());
146 }
147}