cobs/
dec.rs

1/// The [`CobsDecoder`] type is used to decode a stream of bytes to a
2/// given mutable output slice. This is often useful when heap data
3/// structures are not available, or when not all message bytes are
4/// received at a single point in time.
5#[derive(Debug)]
6pub struct CobsDecoder<'a> {
7    /// Destination slice for decoded message
8    dest: &'a mut [u8],
9
10    /// Index of next byte to write in `dest`
11    dest_idx: usize,
12
13    /// Decoder state as an enum
14    state: DecoderState,
15}
16
17/// The [`DecoderState`] is used to track the current state of a
18/// streaming decoder. This struct does not contain the output buffer
19/// (or a reference to one), and can be used when streaming the decoded
20/// output to a custom data type.
21#[derive(Debug)]
22pub enum DecoderState {
23    /// State machine has not received any non-zero bytes
24    Idle,
25
26    /// 1-254 bytes, can be header or 00
27    Grab(u8),
28
29    /// 255 bytes, will be a header next
30    GrabChain(u8),
31}
32
33fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), ()> {
34    *to.get_mut(idx)
35        .ok_or_else(|| ())? = data;
36    Ok(())
37}
38
39/// [`DecodeResult`] represents the possible non-error outcomes of
40/// pushing an encoded data byte into the [`DecoderState`] state machine
41pub enum DecodeResult {
42    /// The given input byte did not prompt an output byte, either because the
43    /// state machine is still idle, or we have just processed a header byte.
44    /// More data is needed to complete the message.
45    NoData,
46
47    /// We have received a complete and well-encoded COBS message. The
48    /// contents of the associated output buffer may now be used
49    DataComplete,
50
51    /// The following byte should be appended to the current end of the decoded
52    /// output buffer.
53    /// More data is needed to complete the message.
54    DataContinue(u8),
55}
56
57impl DecoderState {
58    /// Push a single encoded byte into the state machine. If the input was
59    /// unexpected, such as an early end of a framed message segment, an Error will
60    /// be returned, and the current associated output buffer contents should be discarded.
61    ///
62    /// If a complete message is indicated, the decoding state machine will automatically
63    /// reset itself to the Idle state, and may be used to begin decoding another message.
64    ///
65    /// NOTE: Sentinel value must be included in the input to this function for the
66    /// decoding to complete
67    pub fn feed(&mut self, data: u8) -> Result<DecodeResult, ()> {
68        use DecoderState::*;
69        use DecodeResult::*;
70        let (ret, state) = match (&self, data) {
71            // Currently Idle, received a terminator, ignore, stay idle
72            (Idle, 0x00) => (Ok(NoData), Idle),
73
74            // Currently Idle, received a byte indicating the
75            // next 255 bytes have no zeroes, so we will have 254 unmodified
76            // data bytes, then an overhead byte
77            (Idle, 0xFF) => (Ok(NoData), GrabChain(0xFE)),
78
79            // Currently Idle, received a byte indicating there will be a
80            // zero that must be modified in the next 1..=254 bytes
81            (Idle, n)    => (Ok(NoData), Grab(n - 1)),
82
83            // We have reached the end of a data run indicated by an overhead
84            // byte, AND we have recieved the message terminator. This was a
85            // well framed message!
86            (Grab(0), 0x00) => (Ok(DataComplete), Idle),
87
88            // We have reached the end of a data run indicated by an overhead
89            // byte, and the next segment of 254 bytes will have no modified
90            // sentinel bytes
91            (Grab(0), 0xFF) => {
92                (Ok(DataContinue(0)), GrabChain(0xFE))
93            },
94
95            // We have reached the end of a data run indicated by an overhead
96            // byte, and we will treat this byte as a modified sentinel byte.
97            // place the sentinel byte in the output, and begin processing the
98            // next non-sentinel sequence
99            (Grab(0), n) => {
100                (Ok(DataContinue(0)), Grab(n - 1))
101            },
102
103            // We were not expecting the sequence to terminate, but here we are.
104            // Report an error due to early terminated message
105            (Grab(_), 0) => {
106                (Err(()), Idle)
107            }
108
109            // We have not yet reached the end of a data run, decrement the run
110            // counter, and place the byte into the decoded output
111            (Grab(i), n) =>  {
112                (Ok(DataContinue(n)), Grab(*i - 1))
113            },
114
115            // We have reached the end of a data run indicated by an overhead
116            // byte, AND we have recieved the message terminator. This was a
117            // well framed message!
118            (GrabChain(0), 0x00) => {
119                (Ok(DataComplete), Idle)
120            }
121
122            // We have reached the end of a data run, and we will begin another
123            // data run with an overhead byte expected at the end
124            (GrabChain(0), 0xFF) => (Ok(NoData), GrabChain(0xFE)),
125
126            // We have reached the end of a data run, and we will expect `n` data
127            // bytes unmodified, followed by a sentinel byte that must be modified
128            (GrabChain(0), n) => (Ok(NoData), Grab(n - 1)),
129
130            // We were not expecting the sequence to terminate, but here we are.
131            // Report an error due to early terminated message
132            (GrabChain(_), 0) => {
133                (Err(()), Idle)
134            }
135
136            // We have not yet reached the end of a data run, decrement the run
137            // counter, and place the byte into the decoded output
138            (GrabChain(i), n) => {
139                (Ok(DataContinue(n)), GrabChain(*i - 1))
140            },
141        };
142
143        *self = state;
144        ret
145    }
146}
147
148impl<'a> CobsDecoder<'a> {
149
150    /// Create a new streaming Cobs Decoder. Provide the output buffer
151    /// for the decoded message to be placed in
152    pub fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> {
153        CobsDecoder {
154            dest,
155            dest_idx: 0,
156            state: DecoderState::Idle,
157        }
158    }
159
160    /// Push a single byte into the streaming CobsDecoder. Return values mean:
161    ///
162    /// * Ok(None) - State machine okay, more data needed
163    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
164    /// * Err(M) - Message decoding failed, and M bytes were written to output
165    ///
166    /// NOTE: Sentinel value must be included in the input to this function for the
167    /// decoding to complete
168    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, usize> {
169        match self.state.feed(data) {
170            Err(()) => Err(self.dest_idx),
171            Ok(DecodeResult::NoData) => Ok(None),
172            Ok(DecodeResult::DataContinue(n)) => {
173                add(self.dest, self.dest_idx, n).map_err(|_| self.dest_idx)?;
174                self.dest_idx += 1;
175                Ok(None)
176            }
177            Ok(DecodeResult::DataComplete) => {
178                Ok(Some(self.dest_idx))
179            }
180        }
181    }
182
183    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
184    ///
185    /// * Ok(None) - State machine okay, more data needed
186    /// * Ok(Some((N, M))) - A message of N bytes was successfully decoded,
187    ///     using M bytes from `data` (and earlier data)
188    /// * Err(J) - Message decoding failed, and J bytes were written to output
189    ///
190    /// NOTE: Sentinel value must be included in the input to this function for the
191    /// decoding to complete
192    pub fn push(&mut self, data: &[u8]) -> Result<Option<(usize, usize)>, usize> {
193        for (consumed_idx, d) in data.iter().enumerate() {
194            let x = self.feed(*d);
195            if let Some(decoded_bytes_ct) = x? {
196                // convert from index to number of bytes consumed
197                return Ok(Some((decoded_bytes_ct, consumed_idx + 1)));
198            }
199        }
200
201        Ok(None)
202    }
203}
204
205// This needs to be a macro because `src` and `dst` could be the same or different.
206macro_rules! decode_raw (
207    ($src:ident, $dst:ident) => ({
208        let mut source_index = 0;
209        let mut dest_index = 0;
210
211        // Stop at the first terminator, if any
212        let src_end = if let Some(end) = $src.iter().position(|b| *b == 0) {
213            end
214        } else {
215            $src.len()
216        };
217
218        while source_index < src_end {
219            let code = $src[source_index];
220
221            if source_index + code as usize > src_end && code != 1 {
222                return Err(());
223            }
224
225            source_index += 1;
226
227            // TODO: There are potential `panic!`s in these dest_index offsets
228            for _ in 1..code {
229                $dst[dest_index] = $src[source_index];
230                source_index += 1;
231                dest_index += 1;
232            }
233
234            if 0xFF != code && source_index < src_end {
235                $dst[dest_index] = 0;
236                dest_index += 1;
237            }
238        }
239
240        DecodeReport {
241            dst_used: dest_index,
242            src_used: source_index,
243        }
244    })
245);
246
247/// Decodes the `source` buffer into the `dest` buffer.
248///
249/// This function uses the typical sentinel value of 0.
250///
251/// # Failures
252///
253/// This will return `Err(())` if there was a decoding error. Otherwise,
254/// it will return `Ok(n)` where `n` is the length of the decoded message.
255pub fn decode(source: &[u8], dest: &mut[u8]) -> Result<usize, ()> {
256    let mut dec = CobsDecoder::new(dest);
257
258    // Did we decode a message, using some or all of the buffer?
259    match dec.push(source).or(Err(()))? {
260        Some((d_used, _s_used)) => return Ok(d_used),
261        None => {},
262    }
263
264    // If we consumed the entire buffer, but did NOT get a message,
265    // AND the message did not end with a zero, try providing one to
266    // complete the decoding.
267    if source.last() != Some(&0) {
268        // Explicitly push sentinel of zero
269        if let Some((d_used, _s_used)) = dec.push(&[0]).or(Err(()))? {
270            return Ok(d_used)
271        }
272    }
273
274    // Nope, no early message, no missing terminator, just failed to decode
275    Err(())
276}
277
278/// A report of the source and destination bytes used during in-place decoding
279#[derive(Debug)]
280pub struct DecodeReport {
281    // The number of source bytes used, NOT INCLUDING the sentinel byte,
282    // if there was one.
283    pub src_used: usize,
284
285    // The number of bytes of the source buffer that now include the
286    // decoded result
287    pub dst_used: usize,
288}
289
290/// Decodes a message in-place.
291///
292/// This is the same function as `decode_in_place`, but provides a report
293/// of both the number of source bytes consumed as well as the size of the
294/// destination used.
295pub fn decode_in_place_report(buff: &mut[u8]) -> Result<DecodeReport, ()> {
296    Ok(decode_raw!(buff, buff))
297}
298
299/// Decodes a message in-place.
300///
301/// This is the same function as `decode`, but replaces the encoded message
302/// with the decoded message instead of writing to another buffer.
303///
304/// The returned `usize` is the number of bytes used for the DECODED value,
305/// NOT the number of source bytes consumed during decoding.
306pub fn decode_in_place(buff: &mut[u8]) -> Result<usize, ()> {
307    Ok(decode_raw!(buff, buff).dst_used)
308}
309
310/// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value.
311///
312/// This is done by XOR-ing each byte of the source message with the chosen sentinel value,
313/// which transforms the message into the same message encoded with a sentinel value of 0.
314/// Then the regular decoding transformation is performed.
315///
316/// The returned `usize` is the number of bytes used for the DECODED value,
317/// NOT the number of source bytes consumed during decoding.
318pub fn decode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> Result<usize, ()> {
319    for (x, y) in source.iter().zip(dest.iter_mut()) {
320        *y = *x ^ sentinel;
321    }
322    decode_in_place(dest)
323}
324
325/// Decodes a message in-place using an arbitrary sentinel value.
326///
327/// The returned `usize` is the number of bytes used for the DECODED value,
328/// NOT the number of source bytes consumed during decoding.
329pub fn decode_in_place_with_sentinel(buff: &mut[u8], sentinel: u8) -> Result<usize, ()> {
330    for x in buff.iter_mut() {
331        *x ^= sentinel;
332    }
333    decode_in_place(buff)
334}
335
336#[cfg(feature = "use_std")]
337/// Decodes the `source` buffer into a vector.
338pub fn decode_vec(source: &[u8]) -> Result<Vec<u8>, ()> {
339    let mut decoded = vec![0; source.len()];
340    match decode(source, &mut decoded[..]) {
341        Ok(n) => {
342            decoded.truncate(n);
343            Ok(decoded)
344        },
345        Err(()) => Err(()),
346    }
347}
348
349#[cfg(feature = "use_std")]
350/// Decodes the `source` buffer into a vector with an arbitrary sentinel value.
351pub fn decode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Result<Vec<u8>, ()> {
352    let mut decoded = vec![0; source.len()];
353    match decode_with_sentinel(source, &mut decoded[..], sentinel) {
354        Ok(n) => {
355            decoded.truncate(n);
356            Ok(decoded)
357        },
358        Err(()) => Err(()),
359    }
360}