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}