[go: up one dir, main page]

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