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}