hackdose_sml_parser/transport/
mod.rs

1/// Builder to read SML messages byte-wise from a stream
2/// ```
3/// use hackdose_sml_parser::transport::SMLMessageBuilder;
4/// let mut builder = SMLMessageBuilder::Empty;
5/// builder.record(&[0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01]);
6/// builder.record(&[0x63, 0x01, 0x02]);
7/// builder.record(&[0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x01,0x02, 0x03]);
8/// assert_eq!(builder, SMLMessageBuilder::Complete{ data: vec![0x63, 0x01, 0x02], rest: vec![]});
9/// ```
10#[derive(Eq, PartialEq, Debug)]
11pub enum SMLMessageBuilder {
12    Empty,
13    IncompleteStartSignature(usize),
14    Recording(Vec<u8>),
15    Complete {
16        /// the body of the message, omitting crc and header/footer
17        data: Vec<u8>,
18        /// the unprocessed rest of the byte stream
19        rest: Vec<u8>,
20    },
21}
22
23static START_SEQUENCE: &[u8] = &[0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01];
24static END_SEQUENCE_WITHOUT_CRC: &[u8] = &[0x1b, 0x1b, 0x1b, 0x1b, 0x1a];
25
26impl SMLMessageBuilder {
27    pub fn record(&mut self, buf: &[u8]) {
28        match self {
29            SMLMessageBuilder::Empty | SMLMessageBuilder::IncompleteStartSignature(_) => {
30                let start = match self {
31                    SMLMessageBuilder::Empty => 0,
32                    SMLMessageBuilder::IncompleteStartSignature(start) => *start,
33                    SMLMessageBuilder::Recording(_) => todo!(),
34                    SMLMessageBuilder::Complete { data: _, rest: _ } => todo!(),
35                };
36                let remainder_of_start_sequence = &START_SEQUENCE[start..];
37                let remaining_start_sequence_bytes = remainder_of_start_sequence.len();
38
39                let buffer_length = buf.len();
40
41                struct MaximalOccurance {
42                    index: usize,
43                    length: usize,
44                }
45                let maximal_start_sequence_occurance = (0..buffer_length)
46                    .map(|i| {
47                        let window = &&buf[buffer_length - i - 1
48                            ..usize::min(
49                                buffer_length,
50                                buffer_length - i - 1 + remainder_of_start_sequence.len(),
51                            )];
52                        let contained_length = contains(window, remainder_of_start_sequence);
53                        if contained_length < remaining_start_sequence_bytes
54                            && i + 1 > contained_length
55                        {
56                            MaximalOccurance {
57                                index: buffer_length - i - 1,
58                                length: 0,
59                            }
60                        } else {
61                            MaximalOccurance {
62                                index: buffer_length - i - 1,
63                                length: contained_length,
64                            }
65                        }
66                    })
67                    .max_by_key(|item| item.length)
68                    .unwrap_or(MaximalOccurance {
69                        index: 0,
70                        length: 0,
71                    });
72
73                if maximal_start_sequence_occurance.length == remaining_start_sequence_bytes {
74                    *self = SMLMessageBuilder::Recording([].to_vec());
75                    self.record(
76                        &buf[maximal_start_sequence_occurance.index
77                            + maximal_start_sequence_occurance.length..]
78                            .to_vec(),
79                    );
80                } else if maximal_start_sequence_occurance.length > 0 {
81                    *self = SMLMessageBuilder::IncompleteStartSignature(
82                        maximal_start_sequence_occurance.length + start,
83                    );
84                } else if maximal_start_sequence_occurance.length == 0 && buf.len() > 0 {
85                    *self = SMLMessageBuilder::Empty;
86                };
87            }
88
89            SMLMessageBuilder::Recording(recorded) => {
90                recorded.append(&mut buf.to_vec());
91                let end = recorded
92                    .windows(END_SEQUENCE_WITHOUT_CRC.len() + 3)
93                    .enumerate()
94                    .find(|(_, x)| x[..END_SEQUENCE_WITHOUT_CRC.len()] == *END_SEQUENCE_WITHOUT_CRC)
95                    .map(|(index, _)| index);
96                if let Some(end) = end {
97                    let (message, rest) = recorded.split_at_mut(end);
98                    *self = SMLMessageBuilder::Complete {
99                        data: message.to_vec(),
100                        rest: rest[END_SEQUENCE_WITHOUT_CRC.len() + 3..].to_vec(),
101                    }
102                }
103            }
104            _ => {}
105        }
106    }
107}
108fn contains(this: &[u8], that: &[u8]) -> usize {
109    let mut counter = 0;
110    for pair in this.iter().zip(that.iter()) {
111        if pair.0 == pair.1 {
112            counter += 1;
113        } else {
114            break;
115        }
116    }
117    counter
118}
119
120#[cfg(test)]
121mod test {
122
123    use super::*;
124
125    #[test]
126    pub fn extends_if_start_of_sequence_is_found() {
127        let buf = vec![0x1b];
128        let mut rec = SMLMessageBuilder::Empty;
129
130        rec.record(&buf);
131        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(1));
132    }
133
134    #[test]
135    pub fn extends_if_start_of_sequence_is_found_anywhere() {
136        let buf = vec![0xbb, 0x1b];
137        let mut rec = SMLMessageBuilder::Empty;
138
139        rec.record(&buf);
140        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(1));
141    }
142
143    #[test]
144    pub fn extends_more_if_bigger_portion_of_sequence_is_found() {
145        let buf = vec![0x1b, 0x1b];
146        let mut rec = SMLMessageBuilder::Empty;
147
148        rec.record(&buf);
149        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(2));
150    }
151
152    #[test]
153    pub fn extends_more_if_even_bigger_portion_of_sequence_is_found() {
154        let buf = vec![0x1b, 0x1b, 0x1b];
155        let mut rec = SMLMessageBuilder::Empty;
156
157        rec.record(&buf);
158        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(3));
159    }
160
161    // incomplete occurences must be at the end
162
163    #[test]
164    pub fn incomplete_occurences_must_be_at_the_end() {
165        let buf = vec![0x1b, 0x1b, 0x1b, 0x77];
166        let mut rec = SMLMessageBuilder::Empty;
167
168        rec.record(&buf);
169        assert_eq!(rec, SMLMessageBuilder::Empty);
170    }
171
172    #[test]
173    pub fn finds_complete_sequence() {
174        let buf = &[0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01];
175
176        let mut rec = SMLMessageBuilder::Empty;
177
178        rec.record(buf);
179        assert_eq!(rec, SMLMessageBuilder::Recording(vec![]));
180    }
181
182    #[test]
183    pub fn extends_existing_start_sequence() {
184        let buf = &[0x1b, 0x1b];
185
186        let mut rec = SMLMessageBuilder::Empty;
187
188        rec.record(buf);
189        rec.record(buf);
190        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(4));
191    }
192
193    #[test]
194    pub fn returns_into_empty_if_start_signature_is_not_continued() {
195        let buf = &[0x1b, 0x1b];
196
197        let mut rec = SMLMessageBuilder::Empty;
198
199        rec.record(buf);
200
201        let buf = &[0x1b, 0x1a];
202
203        rec.record(buf);
204        assert_eq!(rec, SMLMessageBuilder::Empty);
205    }
206
207    #[test]
208    pub fn leaves_unchanged_if_empty_buffer_is_recorded() {
209        let buf = &[0x1b, 0x1b];
210
211        let mut rec = SMLMessageBuilder::Empty;
212
213        rec.record(buf);
214
215        let buf = &[];
216
217        rec.record(buf);
218        assert_eq!(rec, SMLMessageBuilder::IncompleteStartSignature(2));
219    }
220
221    #[test]
222    pub fn finds_complete_sequence_in_two_parts() {
223        let buf = &[0x1b, 0x1b, 0x1b, 0x1b];
224        let buf2 = &[0x01, 0x01, 0x01, 0x01];
225
226        let mut rec = SMLMessageBuilder::Empty;
227
228        rec.record(buf);
229        rec.record(buf2);
230        assert_eq!(rec, SMLMessageBuilder::Recording(vec![]));
231    }
232
233    #[test]
234    pub fn puts_buffer_into_recorder() {
235        let buf = &[0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x42, 0x43];
236
237        let mut rec = SMLMessageBuilder::Empty;
238
239        rec.record(buf);
240        assert_eq!(rec, SMLMessageBuilder::Recording(vec![0x42, 0x43]));
241    }
242
243    #[test]
244    pub fn extends_buffer_when_recording() {
245        let buf = &[0x42, 0x43];
246
247        let mut rec = SMLMessageBuilder::Recording(vec![]);
248
249        rec.record(buf);
250        assert_eq!(rec, SMLMessageBuilder::Recording(vec![0x42, 0x43]));
251    }
252
253    #[test]
254    pub fn extends_recording_buffer() {
255        let buf = &[0x44, 0x45];
256
257        let mut rec = SMLMessageBuilder::Recording(vec![0x42, 0x43]);
258
259        rec.record(buf);
260        assert_eq!(
261            rec,
262            SMLMessageBuilder::Recording(vec![0x42, 0x43, 0x44, 0x45])
263        );
264    }
265
266    #[test]
267    pub fn puts_into_ended_state() {
268        let buf = &[0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x00, 0x01, 0x02, 0x03];
269
270        let mut rec = SMLMessageBuilder::Recording(vec![0x42, 0x43]);
271
272        rec.record(buf);
273        assert_eq!(
274            rec,
275            SMLMessageBuilder::Complete {
276                data: vec![0x42, 0x43],
277                rest: vec![0x03]
278            }
279        );
280    }
281
282    #[test]
283    pub fn keeps_rest() {
284        let buf = &[0x1b, 0x1b, 0x1b, 0x1b, 0x1a, 0x00, 0x01, 0x02, 0x03];
285
286        let mut rec = SMLMessageBuilder::Recording(vec![0x42, 0x43]);
287
288        rec.record(buf);
289        assert_eq!(
290            rec,
291            SMLMessageBuilder::Complete {
292                data: vec![0x42, 0x43],
293                rest: vec![0x03]
294            }
295        );
296    }
297
298    #[test]
299    pub fn accepts_end_signature_in_two_parts() {
300        let buf = &[0x1b, 0x1b, 0x1b, 0x1b];
301
302        let mut rec = SMLMessageBuilder::Recording(vec![0x42, 0x43]);
303
304        rec.record(buf);
305        let buf = &[0x1a, 0x00, 0x01, 0x02, 0x03];
306        rec.record(buf);
307
308        assert_eq!(
309            rec,
310            SMLMessageBuilder::Complete {
311                data: vec![0x42, 0x43],
312                rest: vec![0x03]
313            }
314        );
315    }
316
317    #[test]
318    pub fn perform_recording_and_finishing_in_one_step() {
319        let buf = &[
320            0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x42, 0x43, 0x1b, 0x1b, 0x1b, 0x1b,
321            0x1a, 0x00, 0x01, 0x02,
322        ];
323
324        let mut rec = SMLMessageBuilder::Empty;
325
326        rec.record(buf);
327
328        assert_eq!(
329            rec,
330            SMLMessageBuilder::Complete {
331                data: vec![0x42, 0x43],
332                rest: vec![]
333            }
334        );
335    }
336
337    #[test]
338    pub fn ignores_data_between_end_and_start() {
339        let buf = &[
340            0x7b, 0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x42, 0x43, 0x1b, 0x1b, 0x1b,
341            0x1b, 0x1a, 0x00, 0x01, 0x02,
342        ];
343
344        let mut rec = SMLMessageBuilder::Empty;
345
346        rec.record(buf);
347
348        assert_eq!(
349            rec,
350            SMLMessageBuilder::Complete {
351                data: vec![0x42, 0x43],
352                rest: vec![]
353            }
354        );
355    }
356
357    #[test]
358    pub fn takes_first_of_two_messages() {
359        let buf = &[
360            0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x42, 0x43, 0x1b, 0x1b, 0x1b, 0x1b,
361            0x1a, 0x00, 0x01, 0x02, 0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x43, 0x1b,
362            0x1b, 0x1b, 0x1b, 0x1a, 0x00, 0x02, 0x01,
363        ];
364
365        let mut rec = SMLMessageBuilder::Empty;
366
367        rec.record(buf);
368
369        assert_eq!(
370            rec,
371            SMLMessageBuilder::Complete {
372                data: vec![0x42, 0x43],
373                rest: vec![
374                    0x1b, 0x1b, 0x1b, 0x1b, 0x01, 0x01, 0x01, 0x01, 0x43, 0x1b, 0x1b, 0x1b, 0x1b,
375                    0x1a, 0x00, 0x02, 0x01
376                ]
377            }
378        );
379    }
380}