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 // Stop at the first terminator, if any
212 let src_end = if let Some(end) = $src.iter().position(|b| *b == 0) {
213 end
214 } else {
215 $src.len()
216 };
217
218 while source_index < src_end {
219 let code = $src[source_index];
220
221 if source_index + code as usize > src_end && code != 1 {
222 return Err(());
223 }
224
225 source_index += 1;
226
227 // TODO: There are potential `panic!`s in these dest_index offsets
228 for _ in 1..code {
229 $dst[dest_index] = $src[source_index];
230 source_index += 1;
231 dest_index += 1;
232 }
233
234 if 0xFF != code && source_index < src_end {
235 $dst[dest_index] = 0;
236 dest_index += 1;
237 }
238 }
239
240 DecodeReport {
241 dst_used: dest_index,
242 src_used: source_index,
243 }
244 })
245);
246
247/// Decodes the `source` buffer into the `dest` buffer.
248///
249/// This function uses the typical sentinel value of 0.
250///
251/// # Failures
252///
253/// This will return `Err(())` if there was a decoding error. Otherwise,
254/// it will return `Ok(n)` where `n` is the length of the decoded message.
255pub fn decode(source: &[u8], dest: &mut[u8]) -> Result<usize, ()> {
256 let mut dec = CobsDecoder::new(dest);
257
258 // Did we decode a message, using some or all of the buffer?
259 match dec.push(source).or(Err(()))? {
260 Some((d_used, _s_used)) => return Ok(d_used),
261 None => {},
262 }
263
264 // If we consumed the entire buffer, but did NOT get a message,
265 // AND the message did not end with a zero, try providing one to
266 // complete the decoding.
267 if source.last() != Some(&0) {
268 // Explicitly push sentinel of zero
269 if let Some((d_used, _s_used)) = dec.push(&[0]).or(Err(()))? {
270 return Ok(d_used)
271 }
272 }
273
274 // Nope, no early message, no missing terminator, just failed to decode
275 Err(())
276}
277
278/// A report of the source and destination bytes used during in-place decoding
279#[derive(Debug)]
280pub struct DecodeReport {
281 // The number of source bytes used, NOT INCLUDING the sentinel byte,
282 // if there was one.
283 pub src_used: usize,
284
285 // The number of bytes of the source buffer that now include the
286 // decoded result
287 pub dst_used: usize,
288}
289
290/// Decodes a message in-place.
291///
292/// This is the same function as `decode_in_place`, but provides a report
293/// of both the number of source bytes consumed as well as the size of the
294/// destination used.
295pub fn decode_in_place_report(buff: &mut[u8]) -> Result<DecodeReport, ()> {
296 Ok(decode_raw!(buff, buff))
297}
298
299/// Decodes a message in-place.
300///
301/// This is the same function as `decode`, but replaces the encoded message
302/// with the decoded message instead of writing to another buffer.
303///
304/// The returned `usize` is the number of bytes used for the DECODED value,
305/// NOT the number of source bytes consumed during decoding.
306pub fn decode_in_place(buff: &mut[u8]) -> Result<usize, ()> {
307 Ok(decode_raw!(buff, buff).dst_used)
308}
309
310/// Decodes the `source` buffer into the `dest` buffer using an arbitrary sentinel value.
311///
312/// This is done by XOR-ing each byte of the source message with the chosen sentinel value,
313/// which transforms the message into the same message encoded with a sentinel value of 0.
314/// Then the regular decoding transformation is performed.
315///
316/// The returned `usize` is the number of bytes used for the DECODED value,
317/// NOT the number of source bytes consumed during decoding.
318pub fn decode_with_sentinel(source: &[u8], dest: &mut[u8], sentinel: u8) -> Result<usize, ()> {
319 for (x, y) in source.iter().zip(dest.iter_mut()) {
320 *y = *x ^ sentinel;
321 }
322 decode_in_place(dest)
323}
324
325/// Decodes a message in-place using an arbitrary sentinel value.
326///
327/// The returned `usize` is the number of bytes used for the DECODED value,
328/// NOT the number of source bytes consumed during decoding.
329pub fn decode_in_place_with_sentinel(buff: &mut[u8], sentinel: u8) -> Result<usize, ()> {
330 for x in buff.iter_mut() {
331 *x ^= sentinel;
332 }
333 decode_in_place(buff)
334}
335
336#[cfg(feature = "use_std")]
337/// Decodes the `source` buffer into a vector.
338pub fn decode_vec(source: &[u8]) -> Result<Vec<u8>, ()> {
339 let mut decoded = vec![0; source.len()];
340 match decode(source, &mut decoded[..]) {
341 Ok(n) => {
342 decoded.truncate(n);
343 Ok(decoded)
344 },
345 Err(()) => Err(()),
346 }
347}
348
349#[cfg(feature = "use_std")]
350/// Decodes the `source` buffer into a vector with an arbitrary sentinel value.
351pub fn decode_vec_with_sentinel(source: &[u8], sentinel: u8) -> Result<Vec<u8>, ()> {
352 let mut decoded = vec![0; source.len()];
353 match decode_with_sentinel(source, &mut decoded[..], sentinel) {
354 Ok(n) => {
355 decoded.truncate(n);
356 Ok(decoded)
357 },
358 Err(()) => Err(()),
359 }
360}