Skip to main content

noalloc_slip_rs/
slip.rs

1use core::ops::Deref;
2
3use noalloc_vec_rs::vec::Vec;
4
5pub const END_CHAR: u8 = 0xC0;
6pub const ESC_CHAR: u8 = 0xDB;
7pub const ESC_END_CHAR: u8 = 0xDC;
8pub const ESC_ESC_CHAR: u8 = 0xDD;
9
10/// A SLIP encoder.
11///
12/// This struct provides a method to encode a packet using the SLIP protocol.
13pub struct SlipEncoder;
14
15impl SlipEncoder {
16    /// Takes a reference to a Vec and encodes it in place.
17    /// The Vec must have enough capacity to hold the encoded packet.
18    ///
19    /// # Arguments
20    ///
21    /// * `vec` - A reference to a Vec containing the packet to encode.
22    ///
23    /// # Returns
24    ///
25    /// * `Ok(())` if the packet was encoded successfully.
26    /// * `Err(())` if the packet could not be encoded.
27    #[allow(clippy::result_unit_err)]
28    pub fn encode<const MAX_LENGTH: usize>(vec: &mut Vec<u8, MAX_LENGTH>) -> Result<(), ()> {
29        // Begin the SLIP frame
30        vec.insert(0, END_CHAR)?;
31
32        let mut index = 1;
33        while index < vec.len() {
34            match vec[index] {
35                END_CHAR => {
36                    vec.insert(index, ESC_CHAR)?;
37                    vec.write(index + 1, ESC_END_CHAR)?;
38                    index += 2;
39                }
40                ESC_CHAR => {
41                    vec.insert(index, ESC_CHAR)?;
42                    vec.write(index + 1, ESC_ESC_CHAR)?;
43                    index += 2;
44                }
45                _ => {
46                    index += 1;
47                }
48            }
49        }
50
51        // End the SLIP frame
52        vec.insert(vec.len(), END_CHAR)?;
53
54        Ok(())
55    }
56}
57
58/// The state of the SLIP decoder.
59#[derive(Debug, Default, PartialEq)]
60enum SlipDecoderState {
61    /// The decoder is waiting for the start of a packet.
62    #[default]
63    Start,
64    /// The decoder has reached the end of a packet.
65    End,
66    /// The decoder is appending bytes to the packet.
67    Append,
68    /// The decoder has encountered an escape character.
69    Escape,
70}
71
72/// A SLIP decoder.
73///
74/// This struct provides methods to decode a packet using the SLIP protocol.
75#[derive(Default)]
76pub struct SlipDecoder<const MAX_LENGTH: usize> {
77    /// The current state of the decoder.
78    state: SlipDecoderState,
79    /// The buffer containing the decoded packet.
80    buffer: Vec<u8, MAX_LENGTH>,
81}
82
83impl<const MAX_LENGTH: usize> SlipDecoder<MAX_LENGTH> {
84    /// Takes a byte and inserts it into the decoder.
85    ///
86    /// # Arguments
87    ///
88    /// * `value` - The byte to insert.
89    ///
90    /// # Returns
91    ///
92    /// * `Ok(())` if the byte was inserted successfully.
93    /// * `Err(())` if the byte could not be inserted.
94    #[allow(clippy::result_unit_err)]
95    pub fn insert(&mut self, value: u8) -> Result<(), ()> {
96        match self.state {
97            SlipDecoderState::Start => {
98                if value == END_CHAR {
99                    self.state = SlipDecoderState::Append;
100                }
101
102                Ok(())
103            }
104            SlipDecoderState::Append => {
105                match value {
106                    END_CHAR => {
107                        self.state = SlipDecoderState::End;
108                    }
109                    ESC_CHAR => {
110                        self.state = SlipDecoderState::Escape;
111                    }
112                    _ => {
113                        self.buffer.push(value)?;
114                    }
115                }
116
117                Ok(())
118            }
119            SlipDecoderState::Escape => {
120                self.state = SlipDecoderState::Append;
121
122                match value {
123                    ESC_END_CHAR => {
124                        self.buffer.push(END_CHAR)?;
125
126                        Ok(())
127                    }
128                    ESC_ESC_CHAR => {
129                        self.buffer.push(ESC_CHAR)?;
130
131                        Ok(())
132                    }
133                    _ => Err(()),
134                }
135            }
136            SlipDecoderState::End => Err(()),
137        }
138    }
139
140    /// Resets the decoder to its initial state.
141    pub fn reset(&mut self) {
142        self.state = SlipDecoderState::Start;
143        self.buffer.clear();
144    }
145
146    /// Returns true if the decoder has reached the end of a packet.
147    ///
148    /// # Returns
149    ///
150    /// * `true` if the buffer is completed.
151    /// * `false` otherwise.
152    #[must_use]
153    pub fn is_buffer_completed(&self) -> bool {
154        self.state == SlipDecoderState::End
155    }
156
157    /// Returns a reference to the buffer containing the decoded packet.
158    ///
159    /// # Returns
160    ///
161    /// * A reference to the buffer.
162    #[must_use]
163    pub const fn get_buffer(&self) -> &[u8] {
164        self.buffer.as_slice()
165    }
166}
167
168/// Deref to get the internal buffer.
169impl<const MAX_LENGTH: usize> Deref for SlipDecoder<MAX_LENGTH> {
170    type Target = [u8];
171
172    fn deref(&self) -> &Self::Target {
173        self.get_buffer()
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use crate::slip::END_CHAR;
180    use crate::slip::ESC_CHAR;
181    use crate::slip::ESC_END_CHAR;
182    use crate::slip::ESC_ESC_CHAR;
183    use crate::slip::SlipDecoder;
184    use crate::slip::SlipDecoderState;
185    use crate::slip::SlipEncoder;
186    use noalloc_vec_rs::vec::Vec;
187
188    #[test]
189    fn test_encode() {
190        let mut array = Vec::<u8, 12>::from([0x00, 0x01, 0x02, 0x03]);
191
192        let result = SlipEncoder::encode(&mut array);
193
194        assert!(result.is_ok());
195        assert_eq!(*array, [END_CHAR, 0x00, 0x01, 0x02, 0x03, END_CHAR]);
196    }
197
198    #[test]
199    fn test_encode_empty() {
200        let mut array = Vec::<u8, 12>::new();
201
202        let result = SlipEncoder::encode(&mut array);
203
204        assert!(result.is_ok());
205        assert_eq!(*array, [END_CHAR, END_CHAR]);
206    }
207
208    #[test]
209    fn test_encode_with_escape_characters() {
210        let mut array = Vec::<u8, 12>::from([END_CHAR, ESC_CHAR, ESC_END_CHAR, ESC_ESC_CHAR]);
211
212        let result = SlipEncoder::encode(&mut array);
213
214        assert!(result.is_ok());
215        assert_eq!(
216            *array,
217            [
218                END_CHAR,
219                ESC_CHAR,
220                ESC_END_CHAR,
221                ESC_CHAR,
222                ESC_ESC_CHAR,
223                ESC_END_CHAR,
224                ESC_ESC_CHAR,
225                END_CHAR
226            ]
227        );
228    }
229
230    #[test]
231    fn test_decode() {
232        let mut slip_decoder = SlipDecoder::<1>::default();
233
234        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
235
236        let result = slip_decoder.insert(END_CHAR);
237        assert!(result.is_ok());
238        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
239
240        let result = slip_decoder.insert(0x00);
241        assert!(result.is_ok());
242        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
243
244        let result = slip_decoder.insert(END_CHAR);
245        assert!(result.is_ok());
246        assert_eq!(slip_decoder.state, SlipDecoderState::End);
247
248        assert!(slip_decoder.is_buffer_completed());
249
250        assert_eq!(slip_decoder.get_buffer(), &[0x00]);
251    }
252
253    #[test]
254    fn test_decode_with_escape_characters() {
255        let mut slip_decoder = SlipDecoder::<6>::default();
256
257        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
258
259        let result = slip_decoder.insert(END_CHAR);
260        assert!(result.is_ok());
261        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
262
263        let result = slip_decoder.insert(ESC_CHAR);
264        assert!(result.is_ok());
265        assert_eq!(slip_decoder.state, SlipDecoderState::Escape);
266
267        let result = slip_decoder.insert(ESC_END_CHAR);
268        assert!(result.is_ok());
269        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
270
271        let result = slip_decoder.insert(ESC_CHAR);
272        assert!(result.is_ok());
273        assert_eq!(slip_decoder.state, SlipDecoderState::Escape);
274
275        let result = slip_decoder.insert(ESC_ESC_CHAR);
276        assert!(result.is_ok());
277        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
278
279        let result = slip_decoder.insert(END_CHAR);
280        assert!(result.is_ok());
281        assert_eq!(slip_decoder.state, SlipDecoderState::End);
282
283        assert!(slip_decoder.is_buffer_completed());
284
285        assert_eq!(slip_decoder.get_buffer(), &[END_CHAR, ESC_CHAR]);
286    }
287
288    #[test]
289    fn test_decode_with_bad_escape_character() {
290        let mut slip_decoder = SlipDecoder::<1>::default();
291
292        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
293
294        let result = slip_decoder.insert(END_CHAR);
295        assert!(result.is_ok());
296        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
297
298        let result = slip_decoder.insert(ESC_CHAR);
299        assert!(result.is_ok());
300        assert_eq!(slip_decoder.state, SlipDecoderState::Escape);
301
302        let result = slip_decoder.insert(0x00);
303        assert!(result.is_err());
304    }
305
306    #[test]
307    fn test_decode_empty() {
308        let mut slip_decoder = SlipDecoder::<0>::default();
309
310        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
311
312        let result = slip_decoder.insert(END_CHAR);
313        assert!(result.is_ok());
314        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
315
316        let result = slip_decoder.insert(END_CHAR);
317        assert!(result.is_ok());
318        assert_eq!(slip_decoder.state, SlipDecoderState::End);
319
320        assert!(slip_decoder.is_buffer_completed());
321
322        assert_eq!(slip_decoder.get_buffer(), &[]);
323    }
324
325    #[test]
326    fn test_decode_and_reset() {
327        let mut slip_decoder = SlipDecoder::<1>::default();
328
329        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
330
331        let result = slip_decoder.insert(END_CHAR);
332        assert!(result.is_ok());
333        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
334
335        let result = slip_decoder.insert(0x00);
336        assert!(result.is_ok());
337        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
338
339        let result = slip_decoder.insert(END_CHAR);
340        assert!(result.is_ok());
341        assert_eq!(slip_decoder.state, SlipDecoderState::End);
342
343        assert!(slip_decoder.is_buffer_completed());
344
345        assert_eq!(slip_decoder.get_buffer(), &[0x00]);
346
347        slip_decoder.reset();
348        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
349        assert!(!slip_decoder.is_buffer_completed());
350    }
351
352    #[test]
353    fn test_decode_with_not_enough_space() {
354        let mut slip_decoder = SlipDecoder::<1>::default();
355
356        assert_eq!(slip_decoder.state, SlipDecoderState::Start);
357
358        let result = slip_decoder.insert(END_CHAR);
359        assert!(result.is_ok());
360        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
361
362        let result = slip_decoder.insert(0x00);
363        assert!(result.is_ok());
364        assert_eq!(slip_decoder.state, SlipDecoderState::Append);
365
366        let result = slip_decoder.insert(0x00);
367        assert!(result.is_err());
368    }
369}