1use crate::WindowSize;
2use std::mem;
3
4pub fn encode_input(bytes: &[u8]) -> impl Iterator<Item = &[u8]> {
5 bytes
6 .split(|b| *b == 0xff)
7 .enumerate()
8 .flat_map(|(n, bytes)| {
9 let mut vec = Vec::<&[u8]>::new();
10 if n > 0 {
11 vec.push(b"\xff\xff");
12 }
13 if !bytes.is_empty() {
14 vec.push(bytes);
15 }
16 vec
17 })
18}
19
20pub fn encode_window_size_change(window_size: WindowSize) -> [u8; 6] {
21 let rows = window_size.rows.to_be_bytes();
22 let columns = window_size.columns.to_be_bytes();
23 [0xff, 0, rows[0], rows[1], columns[0], columns[1]]
24}
25
26pub trait DecodeInputAcceptor<E> {
27 fn input(&mut self, input: &[u8]) -> Result<(), E>;
28 fn window_size_change(&mut self, window_size: WindowSize) -> Result<(), E>;
29}
30
31#[derive(Debug, Default, PartialEq)]
32pub struct DecodeInputRemainder {
33 data: [u8; 5],
34 length: u8,
35}
36
37impl DecodeInputRemainder {
38 pub fn new(remainder: &[u8]) -> Self {
39 let mut res: Self = Default::default();
40 let length = remainder.len();
41 assert!(length <= mem::size_of_val(&res.data));
42 res.data[..length].copy_from_slice(remainder);
43 res.length = length as u8;
44 res
45 }
46
47 pub fn move_to_slice(&mut self, dest: &mut [u8]) -> usize {
48 let length = self.len();
49 dest[..length].copy_from_slice(&self.data[..length]);
50 *self = Self::default();
51 length
52 }
53
54 pub fn len(&self) -> usize {
55 self.length.into()
56 }
57
58 pub fn is_empty(&self) -> bool {
59 self.len() == 0
60 }
61}
62
63#[derive(Debug, PartialEq)]
64pub enum DecodeInputChunk<'a> {
65 Input(&'a [u8]),
66 WindowSizeChange(WindowSize),
67 Remainder(DecodeInputRemainder),
68}
69
70pub struct DecodeInputIterator<'a>(&'a [u8]);
71
72impl<'a> Iterator for DecodeInputIterator<'a> {
73 type Item = DecodeInputChunk<'a>;
74 fn next(&mut self) -> Option<Self::Item> {
75 match self.0 {
76 [] => None,
77 [0xff, 0xff, rest @ ..] => {
78 let res = Some(DecodeInputChunk::Input(&self.0[1..2]));
79 self.0 = rest;
80 res
81 }
82 [0xff, 0, rh, rl, ch, cl, rest @ ..] => {
83 let res = Some(DecodeInputChunk::WindowSizeChange(WindowSize::new(
84 u16::from_be_bytes([*rh, *rl]),
85 u16::from_be_bytes([*ch, *cl]),
86 )));
87 self.0 = rest;
88 res
89 }
90 [0xff, 0, ..] | [0xff] => {
91 let res = Some(DecodeInputChunk::Remainder(DecodeInputRemainder::new(
92 self.0,
93 )));
94 self.0 = b"";
95 res
96 }
97 [0xff, _, rest @ ..] => {
98 let res = Some(DecodeInputChunk::Input(&self.0[..2]));
99 self.0 = rest;
100 res
101 }
102 _ => {
103 let next_0xff = self
104 .0
105 .iter()
106 .position(|b| *b == 0xff)
107 .unwrap_or(self.0.len());
108 let res = Some(DecodeInputChunk::Input(&self.0[..next_0xff]));
109 self.0 = &self.0[next_0xff..];
110 res
111 }
112 }
113 }
114}
115
116pub fn decode_input(input: &[u8]) -> DecodeInputIterator {
117 DecodeInputIterator(input)
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use DecodeInputChunk::*;
124
125 fn assert_encode_input<const N: usize>(input: &[u8], expected: [&[u8]; N]) {
126 assert_eq!(
127 Vec::from_iter(encode_input(input)),
128 Vec::from_iter(expected)
129 );
130 }
131
132 #[test]
133 fn encode_input_empty() {
134 assert_encode_input(b"", []);
135 }
136
137 #[test]
138 fn encode_input_basic() {
139 assert_encode_input(b"abc", [b"abc"]);
140 }
141
142 #[test]
143 fn encode_input_leading_escape() {
144 assert_encode_input(b"\xffabcdef", [b"\xff\xff", b"abcdef"]);
145 }
146
147 #[test]
148 fn encode_input_leading_escapes() {
149 assert_encode_input(
150 b"\xff\xff\xffabcdef",
151 [b"\xff\xff", b"\xff\xff", b"\xff\xff", b"abcdef"],
152 );
153 }
154
155 #[test]
156 fn encode_input_only_escape() {
157 assert_encode_input(b"\xff", [b"\xff\xff"]);
158 }
159
160 #[test]
161 fn encode_input_only_escapes() {
162 assert_encode_input(b"\xff\xff\xff", [b"\xff\xff", b"\xff\xff", b"\xff\xff"]);
163 }
164
165 #[test]
166 fn encode_input_trailing_escape() {
167 assert_encode_input(b"abcdef\xff", [b"abcdef", b"\xff\xff"]);
168 }
169
170 #[test]
171 fn encode_input_trailing_escapes() {
172 assert_encode_input(
173 b"abcdef\xff\xff\xff",
174 [b"abcdef", b"\xff\xff", b"\xff\xff", b"\xff\xff"],
175 );
176 }
177
178 #[test]
179 fn encode_input_middle_escape() {
180 assert_encode_input(b"abc\xffdef", [b"abc", b"\xff\xff", b"def"]);
181 }
182
183 #[test]
184 fn encode_input_middle_escapes() {
185 assert_encode_input(
186 b"abc\xff\xff\xffdef",
187 [b"abc", b"\xff\xff", b"\xff\xff", b"\xff\xff", b"def"],
188 );
189 }
190
191 #[test]
192 fn encode_input_escapes() {
193 assert_encode_input(
194 b"\xffabc\xff\xff\xffdef\xff\xff",
195 [
196 b"\xff\xff",
197 b"abc",
198 b"\xff\xff",
199 b"\xff\xff",
200 b"\xff\xff",
201 b"def",
202 b"\xff\xff",
203 b"\xff\xff",
204 ],
205 );
206 }
207
208 #[test]
209 fn encode_window_size_change_basic() {
210 assert_eq!(
211 encode_window_size_change(WindowSize::new(0x89ab, 0xcdef)),
212 *b"\xff\x00\x89\xab\xcd\xef"
213 );
214 }
215
216 fn assert_decode_input<const N: usize>(input: &[u8], expected: [DecodeInputChunk; N]) {
217 assert_eq!(
218 Vec::from_iter(decode_input(input)),
219 Vec::from_iter(expected),
220 );
221 }
222
223 #[test]
224 fn decode_input_empty() {
225 assert_decode_input(b"", []);
226 }
227
228 #[test]
229 fn decode_input_no_escapes() {
230 assert_decode_input(b"abcdef", [Input(b"abcdef")]);
231 }
232
233 #[test]
234 fn decode_input_escape_short_1_last() {
235 assert_decode_input(
236 b"abcdef\xff",
237 [
238 Input(b"abcdef"),
239 Remainder(DecodeInputRemainder::new(b"\xff")),
240 ],
241 );
242 }
243
244 #[test]
245 fn decode_input_escape_window_short_4_last() {
246 assert_decode_input(
247 b"abcdef\xff\x00",
248 [
249 Input(b"abcdef"),
250 Remainder(DecodeInputRemainder::new(b"\xff\x00")),
251 ],
252 );
253 }
254
255 #[test]
256 fn decode_input_escape_window_short_3_last() {
257 assert_decode_input(
258 b"abcdef\xff\x00\x89",
259 [
260 Input(b"abcdef"),
261 Remainder(DecodeInputRemainder::new(b"\xff\x00\x89")),
262 ],
263 );
264 }
265
266 #[test]
267 fn decode_input_escape_window_short_2_last() {
268 assert_decode_input(
269 b"abcdef\xff\x00\x89\xab",
270 [
271 Input(b"abcdef"),
272 Remainder(DecodeInputRemainder::new(b"\xff\x00\x89\xab")),
273 ],
274 );
275 }
276
277 #[test]
278 fn decode_input_escape_window_short_1_last() {
279 assert_decode_input(
280 b"abcdef\xff\x00\x89\xab\xcd",
281 [
282 Input(b"abcdef"),
283 Remainder(DecodeInputRemainder::new(b"\xff\x00\x89\xab\xcd")),
284 ],
285 );
286 }
287
288 #[test]
289 fn decode_input_escape_window_last() {
290 assert_decode_input(
291 b"abcdef\xff\x00\x89\xab\xcd\xef",
292 [
293 Input(b"abcdef"),
294 WindowSizeChange(WindowSize::new(0x89ab, 0xcdef)),
295 ],
296 );
297 }
298
299 #[test]
300 fn decode_input_escape_escape_last() {
301 assert_decode_input(b"abcdef\xff\xff", [Input(b"abcdef"), Input(b"\xff")]);
302 }
303
304 #[test]
305 fn decode_input_escape_garbage_last() {
306 assert_decode_input(b"abcdef\xff\x01", [Input(b"abcdef"), Input(b"\xff\x01")]);
307 }
308
309 #[test]
310 fn decode_input_kitchen_sink() {
311 assert_decode_input(
312 b"\xff\xff\x00\xff\x00\x89\xab\xcd\xff\xff\xff\xffabc",
313 [
314 Input(b"\xff"),
315 Input(b"\x00"),
316 WindowSizeChange(WindowSize::new(0x89ab, 0xcdff)),
317 Input(b"\xff"),
318 Input(b"\xffa"),
319 Input(b"bc"),
320 ],
321 );
322 }
323}