postcard_cobs/
dec.rs

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