Skip to main content

cobs/
dec.rs

1/// The [`DecoderState`] is used to track the current state of a
2/// streaming decoder. This struct does not contain the output buffer
3/// (or a reference to one), and can be used when streaming the decoded
4/// output to a custom data type.
5#[derive(Debug, Default)]
6pub enum DecoderState {
7    /// State machine has not received any non-zero bytes
8    #[default]
9    Idle,
10
11    /// 1-254 bytes, can be header or 00
12    Grab(u8),
13
14    /// 255 bytes, will be a header next
15    GrabChain(u8),
16}
17
18fn add(to: &mut [u8], idx: usize, data: u8) -> Result<(), DecodeError> {
19    *to.get_mut(idx).ok_or(DecodeError::TargetBufTooSmall)? = data;
20    Ok(())
21}
22
23/// [`DecodeResult`] represents the possible non-error outcomes of
24/// pushing an encoded data byte into the [`DecoderState`] state machine
25#[derive(Debug)]
26pub enum DecodeResult {
27    /// The given input byte did not prompt an output byte, either because the
28    /// state machine is still idle, or we have just processed a header byte.
29    /// More data is needed to complete the message.
30    NoData,
31
32    /// Received start of a new frame.
33    DataStart,
34
35    /// We have received a complete and well-encoded COBS message. The
36    /// contents of the associated output buffer may now be used
37    DataComplete,
38
39    /// The following byte should be appended to the current end of the decoded
40    /// output buffer.
41    /// More data is needed to complete the message.
42    DataContinue(u8),
43}
44
45#[derive(Debug, PartialEq, Eq, thiserror::Error)]
46#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
47#[cfg_attr(feature = "defmt", derive(defmt::Format))]
48pub enum DecodeError {
49    #[error("empty input frame")]
50    EmptyFrame,
51    #[error("frame with invalid format, written {decoded_bytes:?} to decoded buffer")]
52    InvalidFrame {
53        /// Number of bytes written to the decoded buffer.
54        decoded_bytes: usize,
55    },
56    #[error("target buffer too small")]
57    TargetBufTooSmall,
58}
59
60impl DecoderState {
61    /// Feed a single encoded byte into the state machine. If the input was
62    /// unexpected, such as an early end of a framed message segment, an Error will
63    /// be returned, and the current associated output buffer contents should be discarded.
64    ///
65    /// If a complete message is indicated, the decoding state machine will automatically
66    /// reset itself to the Idle state, and may be used to begin decoding another message.
67    ///
68    /// NOTE: Sentinel value must be included in the input to this function for the
69    /// decoding to complete
70    pub fn feed(&mut self, data: u8) -> Result<DecodeResult, DecodeError> {
71        use DecodeResult::*;
72        use DecoderState::*;
73
74        let (ret, state) = match (&self, data) {
75            (Grab(i), n) => {
76                if *i > 0 && n > 0 {
77                    // We have not yet reached the end of a data run, decrement the run
78                    // counter, and place the byte into the decoded output
79                    (Ok(DataContinue(n)), Grab(*i - 1))
80                } else if *i == 0 {
81                    match n {
82                        // We have reached the end of a data run indicated by an overhead
83                        // byte, AND we have received the message terminator. This was a
84                        // well framed message!
85                        0x00 => (Ok(DataComplete), Idle),
86
87                        // We have reached the end of a data run indicated by an overhead
88                        // byte, and the next segment of 254 bytes will have no modified
89                        // sentinel bytes
90                        0xFF => (Ok(DataContinue(0)), GrabChain(0xFE)),
91
92                        // We have reached the end of a data run indicated by an overhead
93                        // byte, and we will treat this byte as a modified sentinel byte.
94                        // place the sentinel byte in the output, and begin processing the
95                        // next non-sentinel sequence
96                        n => (Ok(DataContinue(0)), Grab(n - 1)),
97                    }
98                } else {
99                    // We were not expecting the sequence to terminate, but here we are.
100                    // Report an error due to early terminated message
101                    (Err(DecodeError::InvalidFrame { decoded_bytes: 0 }), Idle)
102                }
103            }
104
105            (GrabChain(i), n) => {
106                if *i > 0 && n > 0 {
107                    // We have not yet reached the end of a data run, decrement the run
108                    // counter, and place the byte into the decoded output
109                    (Ok(DataContinue(n)), GrabChain(*i - 1))
110                } else if *i == 0 {
111                    match n {
112                        // We have reached the end of a data run indicated by an overhead
113                        // byte, AND we have received the message terminator. This was a
114                        // well framed message!
115                        0x00 => (Ok(DataComplete), Idle),
116
117                        // We have reached the end of a data run, and we will begin another
118                        // data run with an overhead byte expected at the end
119                        0xFF => (Ok(NoData), GrabChain(0xFE)),
120
121                        // We have reached the end of a data run, and we will expect `n` data
122                        // bytes unmodified, followed by a sentinel byte that must be modified
123                        n => (Ok(NoData), Grab(n - 1)),
124                    }
125                } else {
126                    // We were not expecting the sequence to terminate, but here we are.
127                    // Report an error due to early terminated message
128                    (Err(DecodeError::InvalidFrame { decoded_bytes: 0 }), Idle)
129                }
130            }
131
132            // Currently Idle, received a terminator, ignore, stay idle
133            (Idle, 0x00) => (Ok(NoData), Idle),
134
135            // Currently Idle, received a byte indicating the
136            // next 255 bytes have no zeroes, so we will have 254 unmodified
137            // data bytes, then an overhead byte
138            (Idle, 0xFF) => (Ok(DataStart), GrabChain(0xFE)),
139
140            // Currently Idle, received a byte indicating there will be a
141            // zero that must be modified in the next 1..=254 bytes
142            (Idle, n) => (Ok(DataStart), Grab(n - 1)),
143        };
144
145        *self = state;
146        ret
147    }
148}
149
150#[derive(Debug, Default)]
151struct CobsDecoderInner {
152    /// Index of next byte to write in `dest`
153    dest_idx: usize,
154
155    /// Decoder state as an enum
156    state: DecoderState,
157}
158
159impl CobsDecoderInner {
160    const fn new() -> Self {
161        Self {
162            dest_idx: 0,
163            state: DecoderState::Idle,
164        }
165    }
166
167    /// Feed a single byte into the streaming CobsDecoder. Return values mean:
168    ///
169    /// * Ok(None) - State machine okay, more data needed
170    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
171    /// * Err([DecodeError]) - Message decoding failed
172    ///
173    /// NOTE: Sentinel value must be included in the input to this function for the
174    /// decoding to complete
175    fn feed(&mut self, dest: &mut [u8], data: u8) -> Result<Option<usize>, DecodeError> {
176        match self.state.feed(data) {
177            Err(_) => Err(DecodeError::InvalidFrame {
178                decoded_bytes: self.dest_idx,
179            }),
180            Ok(DecodeResult::NoData) => Ok(None),
181            Ok(DecodeResult::DataStart) => {
182                self.dest_idx = 0;
183                Ok(None)
184            }
185            Ok(DecodeResult::DataContinue(n)) => {
186                add(dest, self.dest_idx, n)?;
187                self.dest_idx += 1;
188                Ok(None)
189            }
190            Ok(DecodeResult::DataComplete) => Ok(Some(self.dest_idx)),
191        }
192    }
193
194    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
195    ///
196    /// * Ok(None) - State machine okay, more data needed
197    /// * Ok(Some([DecodeReport]))) - A message was successfully decoded. The parse size of the
198    ///   report specifies the consumed bytes of the passed data chunk.
199    /// * Err([DecodeError]) - Message decoding failed
200    ///
201    /// If the decoder is used for continuous decoding, the user must take care of feeding any
202    /// undecoded bytes of the input data back into the decoder. This can be done by
203    /// [Self::push]ing the undecoded bytes (the last X bytes of the input with X being the length
204    /// of the input minus the parsed length) into the decoder after a frame was decoded.
205    ///
206    /// NOTE: Sentinel value must be included in the input to this function for the
207    /// decoding to complete
208    pub fn push(
209        &mut self,
210        dest: &mut [u8],
211        data: &[u8],
212    ) -> Result<Option<DecodeReport>, DecodeError> {
213        for (consumed_idx, byte) in data.iter().enumerate() {
214            let opt_decoded_bytes = self.feed(dest, *byte)?;
215            if let Some(decoded_bytes_ct) = opt_decoded_bytes {
216                // convert from index to number of bytes consumed
217                return Ok(Some(DecodeReport {
218                    frame_size: decoded_bytes_ct,
219                    parsed_size: consumed_idx + 1,
220                }));
221            }
222        }
223
224        Ok(None)
225    }
226}
227
228/// The [`CobsDecoder`] type is used to decode a stream of bytes to a
229/// given mutable output slice. This is often useful when heap data
230/// structures are not available, or when not all message bytes are
231/// received at a single point in time.
232#[derive(Debug)]
233pub struct CobsDecoder<'a> {
234    /// Destination slice for decoded message
235    dest: &'a mut [u8],
236    inner: CobsDecoderInner,
237}
238
239impl<'a> CobsDecoder<'a> {
240    /// Create a new streaming Cobs Decoder. Provide the output buffer
241    /// for the decoded message to be placed in
242    pub const fn new(dest: &'a mut [u8]) -> CobsDecoder<'a> {
243        CobsDecoder {
244            dest,
245            inner: CobsDecoderInner::new(),
246        }
247    }
248
249    /// Feed a single byte into the streaming decoder. Return values mean:
250    ///
251    /// * Ok(None) - State machine okay, more data needed
252    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
253    /// * Err([DecodeError]) - Message decoding failed
254    ///
255    /// NOTE: Sentinel value must be included in the input to this function for the
256    /// decoding to complete
257    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, DecodeError> {
258        self.inner.feed(self.dest, data)
259    }
260
261    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
262    ///
263    /// * Ok(None) - State machine okay, more data needed
264    /// * Ok(Some([DecodeReport]))) - A message was successfully decoded. The parse size of the
265    ///   report specifies the consumed bytes of the passed data chunk.
266    /// * Err([DecodeError]) - Message decoding failed
267    ///
268    /// If the decoder is used for continuous decoding, the user must take care of feeding any
269    /// undecoded bytes of the input data back into the decoder. This can be done by
270    /// [Self::push]ing the undecoded bytes (the last X bytes of the input with X being the length
271    /// of the input minus the parsed length) into the decoder after a frame was decoded.
272    ///
273    /// NOTE: Sentinel value must be included in the input to this function for the
274    /// decoding to complete
275    pub fn push(&mut self, data: &[u8]) -> Result<Option<DecodeReport>, DecodeError> {
276        self.inner.push(self.dest, data)
277    }
278
279    /// Destination buffer which contains decoded frames.
280    #[inline]
281    pub fn dest(&self) -> &[u8] {
282        self.dest
283    }
284
285    /// Destination buffer which contains decoded frames.
286    ///
287    /// This allows using the buffer for other purposes than decoding after a frame was found.
288    /// Changing the buffer in any other state might corrupt a frame which might currently be
289    /// decoded.
290    #[inline]
291    pub fn dest_mut(&mut self) -> &mut [u8] {
292        self.dest
293    }
294}
295
296/// The [`CobsDecoderHeapless`] type is used to decode a stream of bytes to a given mutable output
297/// slice. It owns the heapless decoding buffer.
298///
299/// This structure uses a heapless vector as the decoding buffer to avoid lifetimes.
300#[derive(Default, Debug)]
301pub struct CobsDecoderHeapless<const N: usize> {
302    /// Destination slice for decoded message
303    dest: heapless::Vec<u8, N>,
304    inner: CobsDecoderInner,
305}
306
307impl<const N: usize> CobsDecoderHeapless<N> {
308    /// This constructor internally creates the heapless vector.
309    pub fn new() -> Self {
310        let vec = heapless::Vec::new();
311        Self::new_with_vec(vec)
312    }
313
314    /// This constructor allows passing the heapless vector to use.
315    ///
316    /// This can be useful to place the heapless vector into the static BSS section instead of the
317    /// stack.
318    pub fn new_with_vec(mut vec: heapless::Vec<u8, N>) -> Self {
319        vec.resize(vec.capacity(), 0).unwrap();
320        Self {
321            dest: vec,
322            inner: CobsDecoderInner::new(),
323        }
324    }
325
326    /// Feed a single byte into the streaming decoder. Return values mean:
327    ///
328    /// * Ok(None) - State machine okay, more data needed
329    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
330    /// * Err([DecodeError]) - Message decoding failed
331    ///
332    /// NOTE: Sentinel value must be included in the input to this function for the
333    /// decoding to complete
334    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, DecodeError> {
335        self.inner.feed(&mut self.dest, data)
336    }
337
338    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
339    ///
340    /// * Ok(None) - State machine okay, more data needed
341    /// * Ok(Some([DecodeReport]))) - A message was successfully decoded. The parse size of the
342    ///   report specifies the consumed bytes of the passed data chunk.
343    /// * Err([DecodeError]) - Message decoding failed
344    ///
345    /// If the decoder is used for continuous decoding, the user must take care of feeding any
346    /// undecoded bytes of the input data back into the decoder. This can be done by
347    /// [Self::push]ing the undecoded bytes (the last X bytes of the input with X being the length
348    /// of the input minus the parsed length) into the decoder after a frame was decoded.
349    ///
350    /// NOTE: Sentinel value must be included in the input to this function for the
351    /// decoding to complete
352    pub fn push(&mut self, data: &[u8]) -> Result<Option<DecodeReport>, DecodeError> {
353        self.inner.push(&mut self.dest, data)
354    }
355
356    /// Destination buffer which contains decoded frames.
357    #[inline]
358    pub fn dest(&self) -> &[u8] {
359        &self.dest
360    }
361
362    /// Destination buffer which contains decoded frames.
363    ///
364    /// This allows using the buffer for other purposes than decoding after a frame was found.
365    /// Changing the buffer in any other state might corrupt a frame which might currently be
366    /// decoded.
367    #[inline]
368    pub fn dest_mut(&mut self) -> &mut [u8] {
369        &mut self.dest
370    }
371
372    /// Reset the decoding state machine.
373    #[inline]
374    pub fn reset(&mut self) {
375        self.inner = Default::default();
376    }
377}
378
379/// The [`CobsDecoderOwned`] type is used to decode a stream of bytes to a given mutable output
380/// slice. It owns the decoding buffer.
381///
382/// This structure allocates the buffer once at construction but does not perform
383/// runtime allocations. This simplifies keeping a streaming decoder structure as a field
384/// of a structure because it does not require a lifetime.
385#[cfg(feature = "alloc")]
386#[derive(Debug)]
387pub struct CobsDecoderOwned {
388    /// Destination slice for decoded message
389    dest: alloc::vec::Vec<u8>,
390    inner: CobsDecoderInner,
391}
392
393#[cfg(feature = "alloc")]
394impl CobsDecoderOwned {
395    /// Create a new streaming Cobs Decoder. Provide the output buffer
396    /// for the decoded message to be placed in
397    pub fn new(dest_buf_size: usize) -> Self {
398        Self {
399            dest: alloc::vec![0; dest_buf_size],
400            inner: CobsDecoderInner::new(),
401        }
402    }
403
404    /// Feed a single byte into the streaming decoder. Return values mean:
405    ///
406    /// * Ok(None) - State machine okay, more data needed
407    /// * Ok(Some(N)) - A message of N bytes was successfully decoded
408    /// * Err([DecodeError]) - Message decoding failed
409    ///
410    /// NOTE: Sentinel value must be included in the input to this function for the
411    /// decoding to complete
412    pub fn feed(&mut self, data: u8) -> Result<Option<usize>, DecodeError> {
413        self.inner.feed(&mut self.dest, data)
414    }
415
416    /// Push a slice of bytes into the streaming CobsDecoder. Return values mean:
417    ///
418    /// * Ok(None) - State machine okay, more data needed
419    /// * Ok(Some([DecodeReport]))) - A message was successfully decoded. The parse size of the
420    ///   report specifies the consumed bytes of the passed data chunk.
421    /// * Err([DecodeError]) - Message decoding failed
422    ///
423    /// If the decoder is used for continuous decoding, the user must take care of feeding any
424    /// undecoded bytes of the input data back into the decoder. This can be done by
425    /// [Self::push]ing the undecoded bytes (the last X bytes of the input with X being the length
426    /// of the input minus the parsed length) into the decoder after a frame was decoded.
427    ///
428    /// NOTE: Sentinel value must be included in the input to this function for the
429    /// decoding to complete
430    pub fn push(&mut self, data: &[u8]) -> Result<Option<DecodeReport>, DecodeError> {
431        self.inner.push(&mut self.dest, data)
432    }
433
434    /// Destination buffer which contains decoded frames.
435    #[inline]
436    pub fn dest(&self) -> &[u8] {
437        &self.dest
438    }
439
440    /// Destination buffer which contains decoded frames.
441    ///
442    /// This allows using the buffer for other purposes than decoding after a frame was found.
443    /// Changing the buffer in any other state might corrupt a frame which might currently be
444    /// decoded.
445    #[inline]
446    pub fn dest_mut(&mut self) -> &mut [u8] {
447        &mut self.dest
448    }
449
450    /// Reset the decoding state machine.
451    #[inline]
452    pub fn reset(&mut self) {
453        self.inner = Default::default();
454    }
455}
456
457/// Decodes the `source` buffer into the `dest` buffer.
458///
459/// This function uses the typical sentinel value of 0.
460pub fn decode(source: &[u8], dest: &mut [u8]) -> Result<DecodeReport, DecodeError> {
461    if source.is_empty() {
462        return Err(DecodeError::EmptyFrame);
463    }
464
465    let mut dec = CobsDecoder::new(dest);
466
467    // Did we decode a message, using some or all of the buffer?
468    if let Some(result) = dec.push(source)? {
469        return Ok(result);
470    }
471
472    // If we consumed the entire buffer, but did NOT get a message,
473    // AND the message did not end with a zero, try providing one to
474    // complete the decoding.
475    if source.last() != Some(&0) {
476        // Explicitly push sentinel of zero
477        if let Some(result) = dec.push(&[0])? {
478            return Ok(DecodeReport {
479                frame_size: result.frame_size(),
480                parsed_size: source.len(),
481            });
482        }
483    }
484
485    // Nope, no early message, no missing terminator, just failed to decode
486    Err(DecodeError::InvalidFrame {
487        decoded_bytes: dec.inner.dest_idx,
488    })
489}
490
491/// A report of the source and destination bytes used during in-place decoding
492#[derive(Debug, Copy, Clone, PartialEq, Eq)]
493#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
494#[cfg_attr(feature = "defmt", derive(defmt::Format))]
495pub struct DecodeReport {
496    parsed_size: usize,
497    frame_size: usize,
498}
499
500impl DecodeReport {
501    /// The number of source bytes parsed.
502    #[inline]
503    pub fn parsed_size(&self) -> usize {
504        self.parsed_size
505    }
506
507    /// The decoded frame size.
508    #[inline]
509    pub fn frame_size(&self) -> usize {
510        self.frame_size
511    }
512}
513
514/// Decodes a message in-place.
515///
516/// This is the same function as [decode_in_place], but provides a report
517/// of both the number of source bytes consumed as well as the size of the
518/// destination used.
519pub fn decode_in_place_report(buf: &mut [u8]) -> Result<DecodeReport, DecodeError> {
520    let mut source_index = 0;
521    let mut dest_index = 0;
522
523    if buf.is_empty() {
524        return Err(DecodeError::EmptyFrame);
525    }
526
527    // Stop at the first terminator, if any
528    let src_end = if let Some(end) = buf.iter().position(|b| *b == 0) {
529        end
530    } else {
531        buf.len()
532    };
533
534    while source_index < src_end {
535        let code = buf[source_index];
536
537        if source_index + code as usize > src_end && code != 1 {
538            return Err(DecodeError::InvalidFrame {
539                decoded_bytes: dest_index,
540            });
541        }
542
543        source_index += 1;
544
545        for _ in 1..code {
546            *buf.get_mut(dest_index)
547                .ok_or(DecodeError::TargetBufTooSmall)? = buf[source_index];
548            source_index += 1;
549            dest_index += 1;
550        }
551
552        if 0xFF != code && source_index < src_end {
553            *buf.get_mut(dest_index)
554                .ok_or(DecodeError::TargetBufTooSmall)? = 0;
555            dest_index += 1;
556        }
557    }
558
559    Ok(DecodeReport {
560        frame_size: dest_index,
561        parsed_size: source_index,
562    })
563}
564
565/// Decodes a message in-place.
566///
567/// This is the same function as [decode], but replaces the encoded message
568/// with the decoded message instead of writing to another buffer.
569///
570/// The returned `usize` is the number of bytes used for the DECODED value,
571/// NOT the number of source bytes consumed during decoding.
572pub fn decode_in_place(buff: &mut [u8]) -> Result<usize, DecodeError> {
573    decode_in_place_report(buff).map(|res| res.frame_size())
574}
575
576/// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value.
577///
578/// This is done by XOR-ing each byte of the source message with the chosen sentinel value,
579/// which transforms the message into the same message encoded with a sentinel value of 0.
580/// Then the regular decoding transformation is performed.
581///
582/// The returned `usize` is the number of bytes used for the DECODED value,
583/// NOT the number of source bytes consumed during decoding.
584pub fn decode_with_sentinel(
585    source: &[u8],
586    dest: &mut [u8],
587    sentinel: u8,
588) -> Result<usize, DecodeError> {
589    for (x, y) in source.iter().zip(dest.iter_mut()) {
590        *y = *x ^ sentinel;
591    }
592    decode_in_place(dest)
593}
594
595/// Decodes a message in-place using an arbitrary sentinel value.
596///
597/// The returned `usize` is the number of bytes used for the DECODED value,
598/// NOT the number of source bytes consumed during decoding.
599pub fn decode_in_place_with_sentinel(buff: &mut [u8], sentinel: u8) -> Result<usize, DecodeError> {
600    for x in buff.iter_mut() {
601        *x ^= sentinel;
602    }
603    decode_in_place(buff)
604}
605
606#[cfg(feature = "alloc")]
607/// Decodes the `source` buffer into a vector.
608pub fn decode_vec(source: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
609    let mut decoded = alloc::vec![0; source.len()];
610    let result = decode(source, &mut decoded[..])?;
611    decoded.truncate(result.frame_size());
612    Ok(decoded)
613}
614
615#[cfg(feature = "alloc")]
616/// Decodes the `source` buffer into a vector with an arbitrary sentinel value.
617pub fn decode_vec_with_sentinel(
618    source: &[u8],
619    sentinel: u8,
620) -> Result<alloc::vec::Vec<u8>, DecodeError> {
621    let mut decoded = alloc::vec![0; source.len()];
622    let n = decode_with_sentinel(source, &mut decoded[..], sentinel)?;
623    decoded.truncate(n);
624    Ok(decoded)
625}
626
627#[deprecated(since = "0.5.0", note = "use DecodeReport instead")]
628pub type DecodingResult = DecodeReport;
629
630#[cfg(test)]
631mod tests {
632    use crate::{encode, encode_vec_including_sentinels};
633
634    use super::*;
635
636    #[test]
637    fn decode_malformed() {
638        let malformed_buf: [u8; 32] = [
639            68, 69, 65, 68, 66, 69, 69, 70, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
640            0, 0, 0, 0, 0, 0,
641        ];
642        let mut dest_buf: [u8; 32] = [0; 32];
643        if let Err(DecodeError::InvalidFrame { decoded_bytes }) =
644            decode(&malformed_buf, &mut dest_buf)
645        {
646            assert_eq!(decoded_bytes, 7);
647        } else {
648            panic!("decoding worked when it should not have");
649        }
650    }
651
652    #[test]
653    fn decode_empty() {
654        #[cfg(feature = "alloc")]
655        matches!(decode_vec(&[]).unwrap_err(), DecodeError::EmptyFrame);
656        matches!(
657            decode_in_place(&mut []).unwrap_err(),
658            DecodeError::EmptyFrame
659        );
660        matches!(
661            decode(&[], &mut [0; 256]).unwrap_err(),
662            DecodeError::EmptyFrame
663        );
664    }
665
666    #[test]
667    fn decode_target_buf_too_small() {
668        let encoded = &[3, 10, 11, 2, 12];
669        let expected_decoded_len = 4;
670        for i in 0..expected_decoded_len - 1 {
671            let mut dest = alloc::vec![0; i];
672            let result = decode(encoded, &mut dest);
673            assert_eq!(result, Err(DecodeError::TargetBufTooSmall));
674        }
675    }
676
677    fn continuous_decoding(decoder: &mut CobsDecoder, expected_data: &[u8], encoded_frame: &[u8]) {
678        for _ in 0..10 {
679            for byte in encoded_frame.iter().take(encoded_frame.len() - 1) {
680                decoder.feed(*byte).unwrap();
681            }
682            if let Ok(Some(sz_msg)) = decoder.feed(encoded_frame[encoded_frame.len() - 1]) {
683                assert_eq!(sz_msg, expected_data.len());
684                assert_eq!(expected_data, &decoder.dest()[0..sz_msg]);
685            } else {
686                panic!("decoding call did not yield expected frame");
687            }
688        }
689    }
690
691    fn continuous_decoding_heapless(
692        decoder: &mut CobsDecoderHeapless<32>,
693        expected_data: &[u8],
694        encoded_frame: &[u8],
695    ) {
696        for _ in 0..10 {
697            for byte in encoded_frame.iter().take(encoded_frame.len() - 1) {
698                decoder.feed(*byte).unwrap();
699            }
700            if let Ok(Some(sz_msg)) = decoder.feed(encoded_frame[encoded_frame.len() - 1]) {
701                assert_eq!(sz_msg, expected_data.len());
702                assert_eq!(expected_data, &decoder.dest()[0..sz_msg]);
703            } else {
704                panic!("decoding call did not yield expected frame");
705            }
706        }
707    }
708
709    fn continuous_decoding_owned(
710        decoder: &mut CobsDecoderOwned,
711        expected_data: &[u8],
712        encoded_frame: &[u8],
713    ) {
714        for _ in 0..10 {
715            for byte in encoded_frame.iter().take(encoded_frame.len() - 1) {
716                decoder.feed(*byte).unwrap();
717            }
718            if let Ok(Some(sz_msg)) = decoder.feed(encoded_frame[encoded_frame.len() - 1]) {
719                assert_eq!(sz_msg, expected_data.len());
720                assert_eq!(expected_data, &decoder.dest()[0..sz_msg]);
721            } else {
722                panic!("decoding call did not yield expected frame");
723            }
724        }
725    }
726
727    #[test]
728    fn stream_continuously() {
729        let mut dest: [u8; 16] = [0; 16];
730        let data = b"hello world";
731        let mut encoded_data: [u8; 16] = [0; 16];
732        let mut encoded_len = encode(data, &mut encoded_data);
733        // Sentinel byte at end.
734        encoded_data[encoded_len] = 0x00;
735        encoded_len += 1;
736        // Stream continuously using only `push`. The decoding buffer should not overflow.
737        let mut decoder = CobsDecoder::new(&mut dest);
738        continuous_decoding(&mut decoder, data, &encoded_data[0..encoded_len]);
739    }
740
741    #[test]
742    fn stream_continuously_owned() {
743        let data = b"hello world";
744        let mut encoded_data: [u8; 16] = [0; 16];
745        let mut encoded_len = encode(data, &mut encoded_data);
746        // Sentinel byte at end.
747        encoded_data[encoded_len] = 0x00;
748        encoded_len += 1;
749        // Stream continuously using only `push`. The decoding buffer should not overflow.
750        let mut decoder = CobsDecoderOwned::new(32);
751        continuous_decoding_owned(&mut decoder, data, &encoded_data[0..encoded_len]);
752    }
753
754    #[test]
755    fn stream_continuously_heapless() {
756        let data = b"hello world";
757        let mut encoded_data: [u8; 16] = [0; 16];
758        let mut encoded_len = encode(data, &mut encoded_data);
759        // Sentinel byte at end.
760        encoded_data[encoded_len] = 0x00;
761        encoded_len += 1;
762        // Stream continuously using only `push`. The decoding buffer should not overflow.
763        let mut decoder = CobsDecoderHeapless::new();
764        continuous_decoding_heapless(&mut decoder, data, &encoded_data[0..encoded_len]);
765    }
766
767    #[test]
768    fn stream_continuously_2() {
769        let mut dest: [u8; 16] = [0; 16];
770        let data = b"hello world";
771        let mut encoded_data: [u8; 16] = [0; 16];
772        let mut encoded_len = encode(data, &mut encoded_data[1..]);
773        // Sentinel byte at start and end.
774        encoded_data[0] = 0x00;
775        encoded_data[encoded_len + 1] = 0x00;
776        encoded_len += 2;
777        // Stream continuously using only `push`. The decoding buffer should not overflow.
778        let mut decoder = CobsDecoder::new(&mut dest);
779        continuous_decoding(&mut decoder, data, &encoded_data[0..encoded_len]);
780    }
781
782    #[test]
783    fn stream_continuously_2_owned() {
784        let data = b"hello world";
785        let mut encoded_data: [u8; 16] = [0; 16];
786        let mut encoded_len = encode(data, &mut encoded_data[1..]);
787        // Sentinel byte at start and end.
788        encoded_data[0] = 0x00;
789        encoded_data[encoded_len + 1] = 0x00;
790        encoded_len += 2;
791        // Stream continuously using only `push`. The decoding buffer should not overflow.
792        let mut decoder = CobsDecoderOwned::new(32);
793        continuous_decoding_owned(&mut decoder, data, &encoded_data[0..encoded_len]);
794    }
795
796    #[test]
797    fn test_owned_decoder_push_function() {
798        let data = b"hello world";
799        let encoded_data = encode_vec_including_sentinels(data);
800        let mut decoder = CobsDecoderOwned::new(32);
801        let report = decoder.push(&encoded_data).unwrap().unwrap();
802        assert_eq!(report.parsed_size(), encoded_data.len());
803        assert_eq!(report.frame_size(), data.len());
804        assert_eq!(&decoder.dest()[0..report.frame_size()], data);
805        assert_eq!(&decoder.dest_mut()[0..report.frame_size()], data);
806    }
807
808    #[test]
809    fn test_decoder_push_function() {
810        let mut dest_buf: [u8; 32] = [0; 32];
811        let data = b"hello world";
812        let encoded_data = encode_vec_including_sentinels(data);
813        let mut decoder = CobsDecoder::new(&mut dest_buf);
814        let report = decoder.push(&encoded_data).unwrap().unwrap();
815        assert_eq!(report.parsed_size(), encoded_data.len());
816        assert_eq!(report.frame_size(), data.len());
817        assert_eq!(&decoder.dest()[0..report.frame_size()], data);
818        assert_eq!(&decoder.dest_mut()[0..report.frame_size()], data);
819    }
820
821    #[test]
822    fn test_decoder_heapless_push_function() {
823        let data = b"hello world";
824        let encoded_data = encode_vec_including_sentinels(data);
825        let mut decoder = CobsDecoderHeapless::<32>::new();
826        let report = decoder.push(&encoded_data).unwrap().unwrap();
827        assert_eq!(report.parsed_size(), encoded_data.len());
828        assert_eq!(report.frame_size(), data.len());
829        assert_eq!(&decoder.dest()[0..report.frame_size()], data);
830        assert_eq!(&decoder.dest_mut()[0..report.frame_size()], data);
831    }
832}