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}