serial_line_ip/
encoder.rs

1use super::*;
2
3/// SLIP encoder context
4#[derive(Clone)]
5pub struct Encoder {
6    /// Just keep track of whether we have encoded the header yet
7    header_written: bool,
8}
9
10/// The return type of `encode` that holds the bytes read and byte written after
11/// the encode operation.
12pub struct EncodeTotals {
13    /// Number of bytes that were read from the input buffer.
14    pub read: usize,
15    /// Number of bytes that were written to the output buffer.
16    pub written: usize,
17}
18
19impl Encoder {
20    /// Create a new context for SLIP encoding
21    pub fn new() -> Self {
22        Encoder {
23            header_written: false,
24        }
25    }
26
27    /// Encode a buffer into a SLIP stream and returns the number of input bytes read
28    /// and output bytes written.
29    pub fn encode(&mut self, input: &[u8], output: &mut [u8]) -> Result<EncodeTotals> {
30        let mut out_byte = 0;
31        if !self.header_written {
32            if output.len() < 1 {
33                return Err(Error::NoOutputSpaceForHeader);
34            }
35
36            output[out_byte] = END;
37            out_byte = 1;
38            self.header_written = true;
39        }
40
41        let mut in_byte = 0;
42        while in_byte < input.len() {
43            match input[in_byte] {
44                ESC => {
45                    if (output.len() - out_byte) < 2 {
46                        break;
47                    }
48                    output[out_byte] = ESC;
49                    output[out_byte + 1] = ESC_ESC;
50                    out_byte += 2;
51                }
52                END => {
53                    if (output.len() - out_byte) < 2 {
54                        break;
55                    }
56                    output[out_byte] = ESC;
57                    output[out_byte + 1] = ESC_END;
58                    out_byte += 2;
59                }
60                _ => {
61                    if (output.len() - out_byte) < 1 {
62                        break;
63                    }
64                    output[out_byte] = input[in_byte];
65                    out_byte += 1;
66                }
67            }
68            in_byte += 1;
69        }
70
71        Ok(EncodeTotals {
72            read: in_byte,
73            written: out_byte,
74        })
75    }
76
77    /// Finish encoding the current packet and return the number of output bytes written.
78    pub fn finish(self, output: &mut [u8]) -> Result<EncodeTotals> {
79        if output.len() < 1 {
80            return Err(Error::NoOutputSpaceForEndByte);
81        }
82        output[0] = END;
83
84        Ok(EncodeTotals {
85            read: 0,
86            written: 1,
87        })
88    }
89}
90
91impl core::ops::AddAssign for EncodeTotals {
92    fn add_assign(&mut self, other: EncodeTotals) {
93        *self = EncodeTotals {
94            read: self.read + other.read,
95            written: self.written + other.written,
96        };
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn empty_encode() {
106        const EXPECTED: [u8; 2] = [0xc0, 0xc0];
107        let mut output: [u8; 32] = [0; 32];
108
109        let mut slip = Encoder::new();
110        let mut totals = slip.encode(&[0; 0], &mut output).unwrap();
111        assert_eq!(0, totals.read);
112        assert_eq!(1, totals.written);
113        totals += slip.finish(&mut output[totals.written..]).unwrap();
114        assert_eq!(0, totals.read);
115        assert_eq!(2, totals.written);
116        assert_eq!(&EXPECTED, &output[..totals.written]);
117    }
118
119    #[test]
120    fn encode_esc_esc_sequence() {
121        const INPUT: [u8; 3] = [0x01, ESC, 0x03];
122        const EXPECTED: [u8; 6] = [0xc0, 0x01, ESC, ESC_ESC, 0x03, 0xc0];
123        let mut output: [u8; 32] = [0; 32];
124
125        let mut slip = Encoder::new();
126        let mut totals = slip.encode(&INPUT, &mut output).unwrap();
127        assert_eq!(2 + INPUT.len(), totals.written);
128        totals += slip.finish(&mut output[totals.written..]).unwrap();
129        assert_eq!(INPUT.len(), totals.read);
130        assert_eq!(3 + INPUT.len(), totals.written);
131        assert_eq!(&EXPECTED, &output[..totals.written]);
132    }
133    #[test]
134    fn encode_end_esc_sequence() {
135        const INPUT: [u8; 3] = [0x01, END, 0x03];
136        const EXPECTED: [u8; 6] = [0xc0, 0x01, ESC, ESC_END, 0x03, 0xc0];
137        let mut output: [u8; 32] = [0; 32];
138
139        let mut slip = Encoder::new();
140        let mut totals = slip.encode(&INPUT, &mut output).unwrap();
141        assert_eq!(2 + INPUT.len(), totals.written);
142        totals += slip.finish(&mut output[totals.written..]).unwrap();
143        assert_eq!(INPUT.len(), totals.read);
144        assert_eq!(3 + INPUT.len(), totals.written);
145        assert_eq!(&EXPECTED, &output[..totals.written]);
146    }
147
148    #[test]
149    fn multi_part_encode() {
150        const INPUT_1: [u8; 4] = [0x01, 0x02, 0x03, ESC];
151        const INPUT_2: [u8; 4] = [0x05, END, 0x07, 0x08];
152        const INPUT_3: [u8; 4] = [0x09, 0x0a, ESC, 0x0c];
153        const EXPECTED: &[u8] = &[
154            0xc0, 0x01, 0x02, 0x03, ESC, ESC_ESC, 0x05, ESC, ESC_END, 0x07, 0x08, 0x09, 0x0a, ESC,
155            ESC_ESC, 0x0c, 0xc0,
156        ];
157        let mut output: [u8; 32] = [0; 32];
158
159        let mut slip = Encoder::new();
160        let mut final_totals = EncodeTotals {
161            read: 0,
162            written: 0,
163        };
164
165        let totals = slip.encode(&INPUT_1, &mut output).unwrap();
166        assert_eq!(INPUT_1.len(), totals.read);
167        assert_eq!(1 + INPUT_1.len() + 1, totals.written);
168        final_totals += totals;
169
170        let totals = slip
171            .encode(&INPUT_2, &mut output[final_totals.written..])
172            .unwrap();
173        assert_eq!(INPUT_2.len(), totals.read);
174        assert_eq!(INPUT_2.len() + 1, totals.written);
175        final_totals += totals;
176
177        let totals = slip
178            .encode(&INPUT_3, &mut output[final_totals.written..])
179            .unwrap();
180        assert_eq!(INPUT_3.len(), totals.read);
181        assert_eq!(INPUT_3.len() + 1, totals.written);
182        final_totals += totals;
183
184        let totals = slip.finish(&mut output[final_totals.written..]).unwrap();
185        assert_eq!(0, totals.read);
186        assert_eq!(1, totals.written);
187        final_totals += totals;
188
189        assert_eq!(EXPECTED, &output[..final_totals.written]);
190    }
191}