postcard/de/flavors.rs
1//! # Deserialization Flavors
2//!
3//! "Flavors" in `postcard` are used as modifiers to the serialization or deserialization
4//! process. Flavors typically modify one or both of the following:
5//!
6//! 1. The source medium of the deserialization, e.g. whether the data is serialized from a `[u8]` slice, or some other container
7//! 2. The format of the deserialization, such as if the original data is encoded in a COBS format, contains a CRC32 checksum
8//! appended to the message, etc.
9//!
10//! Flavors are implemented using the [`Flavor`] trait, which acts as a "middleware" for retrieving the bytes before they
11//! are passed to `serde` for deserialization
12//!
13//! Multiple flavors may be combined to obtain a desired combination of behavior and storage.
14//! When flavors are combined, it is expected that the storage flavor (such as [`Slice`]) is the innermost flavor.
15//!
16//! Custom flavors may be defined by users of the `postcard` crate, however some commonly useful flavors have been provided in
17//! this module. If you think your custom flavor would be useful to others, PRs adding flavors are very welcome!
18//!
19//! ## Usability
20//!
21//! Flavors may not always be convenient to use directly, as they may expose some implementation details of how the
22//! inner workings of the flavor behaves. It is typical to provide a convenience method for using a flavor, to prevent
23//! the user from having to specify generic parameters, setting correct initialization values, or handling the output of
24//! the flavor correctly. See `postcard::from_bytes()` for an example of this.
25//!
26//! ## When to use (multiple) flavors
27//!
28//! Combining flavors are nice for convenience, as they perform potentially multiple steps of
29//! serialization at one time.
30//!
31//! This can often be more memory efficient, as intermediate buffers are not typically required.
32//!
33//! ## When NOT to use (multiple) flavors
34//!
35//! The downside of passing deserialization through multiple steps is that it is typically slower than
36//! performing each step serially. Said simply, "cobs decoding while deserializing" is often slower
37//! than "cobs decode then deserialize", due to the ability to handle longer "runs" of data in each
38//! stage. The downside is that if these stages can not be performed in-place on the buffer, you
39//! will need additional buffers for each stage.
40//!
41//! Additionally, deserializating flavors can be more restrictive or difficult to work with than
42//! serialization flavors, as deserialization may require that the deserialized types borrow some
43//! portion of the original message.
44//!
45//! ## Examples
46//!
47//! ### Using a single flavor
48//!
49//! In the first example, we use the `Slice` flavor, to retrieve the serialized output from a `[u8]` slice.
50//! No other modification is made to the serialization process.
51//!
52//! ```rust
53//! use postcard::{
54//! de_flavors::Slice,
55//! Deserializer,
56//! };
57//! use serde::Deserialize;
58//!
59//! #[derive(Deserialize, Debug, PartialEq)]
60//! struct Tup(u8, u8, u8);
61//!
62//! let msg = [0x04, 0x00, 0x04, 0x01, 0x02, 0x03];
63//! let slice = Slice::new(&msg);
64//! let mut deserializer = Deserializer::from_flavor(slice);
65//! let t = Tup::deserialize(&mut deserializer).unwrap();
66//! assert_eq!(t, Tup(4, 0, 4));
67//! let remainder = deserializer.finalize().unwrap();
68//! assert_eq!(remainder, &[1, 2, 3]);
69//! ```
70
71use crate::{Error, Result};
72use core::marker::PhantomData;
73
74/// The deserialization Flavor trait
75///
76/// This is used as the primary way to decode serialized data from some kind of buffer,
77/// or modify that data in a middleware style pattern.
78///
79/// See the module level docs for an example of how flavors are used.
80pub trait Flavor<'de>: 'de {
81 /// The remaining data of this flavor after deserializing has completed.
82 ///
83 /// Typically, this includes the remaining buffer that was not used for
84 /// deserialization, and in cases of more complex flavors, any additional
85 /// information that was decoded or otherwise calculated during
86 /// the deserialization process.
87 type Remainder: 'de;
88
89 /// The source of data retrieved for deserialization.
90 ///
91 /// This is typically some sort of data buffer, or another Flavor, when
92 /// chained behavior is desired
93 type Source: 'de;
94
95 /// Obtain the next byte for deserialization
96 fn pop(&mut self) -> Result<u8>;
97
98 /// Returns the number of bytes remaining in the message, if known.
99 ///
100 /// # Implementation notes
101 ///
102 /// It is not enforced that this number is exactly correct.
103 /// A flavor may yield less or more bytes than the what is hinted at by
104 /// this function.
105 ///
106 /// `size_hint()` is primarily intended to be used for optimizations such as
107 /// reserving space for deserialized items, but must not be trusted to
108 /// e.g., omit bounds checks in unsafe code. An incorrect implementation of
109 /// `size_hint()` should not lead to memory safety violations.
110 ///
111 /// That said, the implementation should provide a correct estimation,
112 /// because otherwise it would be a violation of the trait’s protocol.
113 ///
114 /// The default implementation returns `None` which is correct for any flavor.
115 fn size_hint(&self) -> Option<usize> {
116 None
117 }
118
119 /// Attempt to take the next `ct` bytes from the serialized message.
120 ///
121 /// This variant borrows the data from the input for zero-copy deserialization. If zero-copy
122 /// deserialization is not necessary, prefer to use `try_take_n_temp` instead.
123 fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]>;
124
125 /// Attempt to take the next `ct` bytes from the serialized message.
126 ///
127 /// This variant does not guarantee that the returned value is borrowed from the input, so it
128 /// cannot be used for zero-copy deserialization, but it also avoids needing to potentially
129 /// allocate a data in a temporary buffer.
130 ///
131 /// This variant should be used instead of `try_take_n`
132 /// if zero-copy deserialization is not necessary.
133 ///
134 /// It is only necessary to implement this method if the flavor requires storing data in a
135 /// temporary buffer in order to implement the borrow semantics, e.g. the `std::io::Read`
136 /// flavor.
137 fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
138 where
139 'de: 'a,
140 {
141 self.try_take_n(ct)
142 }
143
144 /// Complete the deserialization process.
145 ///
146 /// This is typically called separately, after the `serde` deserialization
147 /// has completed.
148 fn finalize(self) -> Result<Self::Remainder>;
149}
150
151/// A simple [`Flavor`] representing the deserialization from a borrowed slice
152pub struct Slice<'de> {
153 // This string starts with the input data and characters are truncated off
154 // the beginning as data is parsed.
155 pub(crate) cursor: *const u8,
156 pub(crate) end: *const u8,
157 pub(crate) _pl: PhantomData<&'de [u8]>,
158}
159
160impl<'de> Slice<'de> {
161 /// Create a new [Slice] from the given buffer
162 pub fn new(sli: &'de [u8]) -> Self {
163 let range = sli.as_ptr_range();
164 Self {
165 cursor: range.start,
166 end: range.end,
167 _pl: PhantomData,
168 }
169 }
170}
171
172impl<'de> Flavor<'de> for Slice<'de> {
173 type Remainder = &'de [u8];
174 type Source = &'de [u8];
175
176 #[inline]
177 fn pop(&mut self) -> Result<u8> {
178 if self.cursor == self.end {
179 Err(Error::DeserializeUnexpectedEnd)
180 } else {
181 // SAFETY: `self.cursor` is in-bounds and won't be incremented past `self.end` as we
182 // have checked above.
183 unsafe {
184 let res = Ok(*self.cursor);
185 self.cursor = self.cursor.add(1);
186 res
187 }
188 }
189 }
190
191 #[inline]
192 fn size_hint(&self) -> Option<usize> {
193 Some((self.end as usize) - (self.cursor as usize))
194 }
195
196 #[inline]
197 fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
198 let remain = (self.end as usize) - (self.cursor as usize);
199 if remain < ct {
200 Err(Error::DeserializeUnexpectedEnd)
201 } else {
202 // SAFETY: `self.cursor` is valid for `ct` elements and won't be incremented past `self.end` as we
203 // have checked above.
204 unsafe {
205 let sli = core::slice::from_raw_parts(self.cursor, ct);
206 self.cursor = self.cursor.add(ct);
207 Ok(sli)
208 }
209 }
210 }
211
212 /// Return the remaining (unused) bytes in the Deserializer
213 fn finalize(self) -> Result<&'de [u8]> {
214 let remain = (self.end as usize) - (self.cursor as usize);
215 // SAFETY: `self.cursor` is valid for `remain` elements
216 unsafe { Ok(core::slice::from_raw_parts(self.cursor, remain)) }
217 }
218}
219
220/// Support for [`std::io`] or `embedded-io` traits
221#[cfg(any(
222 feature = "embedded-io-04",
223 feature = "embedded-io-06",
224 feature = "use-std"
225))]
226pub mod io {
227 use crate::{Error, Result};
228 use core::marker::PhantomData;
229
230 struct SlidingBuffer<'de> {
231 cursor: *mut u8,
232 end: *const u8,
233 _pl: PhantomData<&'de [u8]>,
234 }
235
236 impl<'de> SlidingBuffer<'de> {
237 pub fn new(sli: &'de mut [u8]) -> Self {
238 let range = sli.as_mut_ptr_range();
239 Self {
240 cursor: range.start,
241 end: range.end,
242 _pl: PhantomData,
243 }
244 }
245
246 #[inline]
247 fn take_n(&mut self, ct: usize) -> Result<&'de mut [u8]> {
248 let remain = (self.end as usize) - (self.cursor as usize);
249 let buff = if remain < ct {
250 return Err(Error::DeserializeUnexpectedEnd);
251 } else {
252 // SAFETY: `self.cursor` is valid for `ct` elements and won't be incremented
253 // past `self.end` as we have checked above.
254 unsafe {
255 let sli = core::slice::from_raw_parts_mut(self.cursor, ct);
256 self.cursor = self.cursor.add(ct);
257 sli
258 }
259 };
260
261 Ok(buff)
262 }
263
264 #[inline]
265 fn take_n_temp(&mut self, ct: usize) -> Result<&mut [u8]> {
266 let remain = (self.end as usize) - (self.cursor as usize);
267 let buff = if remain < ct {
268 return Err(Error::DeserializeUnexpectedEnd);
269 } else {
270 unsafe {
271 let sli = core::slice::from_raw_parts_mut(self.cursor, ct);
272 sli
273 }
274 };
275
276 Ok(buff)
277 }
278
279 fn complete(self) -> Result<&'de mut [u8]> {
280 let remain = (self.end as usize) - (self.cursor as usize);
281 // SAFETY: `self.cursor` is valid for `remain` elements
282 unsafe { Ok(core::slice::from_raw_parts_mut(self.cursor, remain)) }
283 }
284 }
285
286 /// Support for [`embedded_io`](crate::eio::embedded_io) traits
287 #[cfg(any(feature = "embedded-io-04", feature = "embedded-io-06"))]
288 pub mod eio {
289 use super::super::Flavor;
290 use super::SlidingBuffer;
291 use crate::{Error, Result};
292
293 /// Wrapper over a [`embedded_io`](crate::eio::embedded_io)::[`Read`](crate::eio::Read) and a sliding buffer to implement the [`Flavor`] trait
294 pub struct EIOReader<'de, T>
295 where
296 T: crate::eio::Read,
297 {
298 reader: T,
299 buff: SlidingBuffer<'de>,
300 }
301
302 impl<'de, T> EIOReader<'de, T>
303 where
304 T: crate::eio::Read,
305 {
306 /// Create a new [`EIOReader`] from a reader and a buffer.
307 ///
308 /// `buff` must have enough space to hold all data read during the deserialisation.
309 pub fn new(reader: T, buff: &'de mut [u8]) -> Self {
310 Self {
311 reader,
312 buff: SlidingBuffer::new(buff),
313 }
314 }
315 }
316
317 impl<'de, T> Flavor<'de> for EIOReader<'de, T>
318 where
319 T: crate::eio::Read + 'de,
320 {
321 type Remainder = (T, &'de mut [u8]);
322 type Source = &'de [u8];
323
324 #[inline]
325 fn pop(&mut self) -> Result<u8> {
326 let mut val = [0; 1];
327 self.reader
328 .read_exact(&mut val)
329 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
330 Ok(val[0])
331 }
332
333 #[inline]
334 fn size_hint(&self) -> Option<usize> {
335 None
336 }
337
338 #[inline]
339 fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
340 let buff = self.buff.take_n(ct)?;
341 self.reader
342 .read_exact(buff)
343 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
344 Ok(buff)
345 }
346
347 #[inline]
348 fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
349 where
350 'de: 'a,
351 {
352 let buff = self.buff.take_n_temp(ct)?;
353 self.reader
354 .read_exact(buff)
355 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
356 Ok(buff)
357 }
358
359 /// Return the remaining (unused) bytes in the Deserializer
360 fn finalize(self) -> Result<(T, &'de mut [u8])> {
361 let buf = self.buff.complete()?;
362 Ok((self.reader, buf))
363 }
364 }
365
366 #[cfg(test)]
367 mod tests {
368 use super::*;
369
370 #[test]
371 fn test_pop() {
372 let mut reader = EIOReader::new(&[0xAA, 0xBB, 0xCC][..], &mut []);
373
374 assert_eq!(reader.pop(), Ok(0xAA));
375 assert_eq!(reader.pop(), Ok(0xBB));
376 assert_eq!(reader.pop(), Ok(0xCC));
377 assert_eq!(reader.pop(), Err(Error::DeserializeUnexpectedEnd));
378 }
379
380 #[test]
381 fn test_try_take_n() {
382 let mut buf = [0; 8];
383 let mut reader = EIOReader::new(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE][..], &mut buf);
384
385 assert_eq!(reader.try_take_n(2), Ok(&[0xAA, 0xBB][..]));
386 assert_eq!(reader.try_take_n(2), Ok(&[0xCC, 0xDD][..]));
387 assert_eq!(reader.try_take_n(2), Err(Error::DeserializeUnexpectedEnd));
388 }
389 }
390 }
391
392 /// Support for [`std::io`] traits
393 #[allow(clippy::module_inception)]
394 #[cfg(feature = "use-std")]
395 pub mod io {
396 use super::super::Flavor;
397 use super::SlidingBuffer;
398 use crate::{Error, Result};
399
400 /// Wrapper over a [`std::io::Read`] and a sliding buffer to implement the [Flavor] trait
401 pub struct IOReader<'de, T>
402 where
403 T: std::io::Read,
404 {
405 reader: T,
406 buff: SlidingBuffer<'de>,
407 }
408
409 impl<'de, T> IOReader<'de, T>
410 where
411 T: std::io::Read,
412 {
413 /// Create a new [`IOReader`] from a reader and a buffer.
414 ///
415 /// `buff` must have enough space to hold all data read during the deserialisation.
416 pub fn new(reader: T, buff: &'de mut [u8]) -> Self {
417 Self {
418 reader,
419 buff: SlidingBuffer::new(buff),
420 }
421 }
422 }
423
424 impl<'de, T> Flavor<'de> for IOReader<'de, T>
425 where
426 T: std::io::Read + 'de,
427 {
428 type Remainder = (T, &'de mut [u8]);
429 type Source = &'de [u8];
430
431 #[inline]
432 fn pop(&mut self) -> Result<u8> {
433 let mut val = [0; 1];
434 self.reader
435 .read_exact(&mut val)
436 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
437 Ok(val[0])
438 }
439
440 #[inline]
441 fn size_hint(&self) -> Option<usize> {
442 None
443 }
444
445 #[inline]
446 fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
447 let buff = self.buff.take_n(ct)?;
448 self.reader
449 .read_exact(buff)
450 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
451 Ok(buff)
452 }
453
454 #[inline]
455 fn try_take_n_temp<'a>(&'a mut self, ct: usize) -> Result<&'a [u8]>
456 where
457 'de: 'a,
458 {
459 let buff = self.buff.take_n_temp(ct)?;
460 self.reader
461 .read_exact(buff)
462 .map_err(|_| Error::DeserializeUnexpectedEnd)?;
463 Ok(buff)
464 }
465
466 /// Return the remaining (unused) bytes in the Deserializer
467 fn finalize(self) -> Result<(T, &'de mut [u8])> {
468 let buf = self.buff.complete()?;
469 Ok((self.reader, buf))
470 }
471 }
472
473 #[cfg(test)]
474 mod tests {
475 use super::*;
476
477 #[test]
478 fn test_pop() {
479 let mut reader = IOReader::new(&[0xAA, 0xBB, 0xCC][..], &mut []);
480
481 assert_eq!(reader.pop(), Ok(0xAA));
482 assert_eq!(reader.pop(), Ok(0xBB));
483 assert_eq!(reader.pop(), Ok(0xCC));
484 assert_eq!(reader.pop(), Err(Error::DeserializeUnexpectedEnd));
485 }
486
487 #[test]
488 fn test_try_take_n() {
489 let mut buf = [0; 8];
490 let mut reader = IOReader::new(&[0xAA, 0xBB, 0xCC, 0xDD, 0xEE][..], &mut buf);
491
492 assert_eq!(reader.try_take_n(2), Ok(&[0xAA, 0xBB][..]));
493 assert_eq!(reader.try_take_n(2), Ok(&[0xCC, 0xDD][..]));
494 assert_eq!(reader.try_take_n(2), Err(Error::DeserializeUnexpectedEnd));
495 }
496 }
497 }
498}
499
500////////////////////////////////////////
501// CRC
502////////////////////////////////////////
503
504/// This Cyclic Redundancy Check flavor applies [the CRC crate's `Algorithm`](https://docs.rs/crc/latest/crc/struct.Algorithm.html) struct on
505/// the serialized data.
506///
507/// The flavor will check the CRC assuming that it has been appended to the bytes.
508/// CRCs are used for error detection when reading data back.
509/// Requires the `crc` feature.
510///
511/// More on CRCs: <https://en.wikipedia.org/wiki/Cyclic_redundancy_check>.
512#[cfg(feature = "use-crc")]
513#[cfg_attr(docsrs, doc(cfg(feature = "use-crc")))]
514pub mod crc {
515 use core::convert::TryInto;
516
517 use crc::Digest;
518 use crc::Width;
519 use serde::Deserialize;
520
521 use super::Flavor;
522 use super::Slice;
523
524 use crate::Deserializer;
525 use crate::Error;
526 use crate::Result;
527
528 /// Manages CRC modifications as a flavor.
529 pub struct CrcModifier<'de, B, W>
530 where
531 B: Flavor<'de>,
532 W: Width,
533 {
534 flav: B,
535 digest: Digest<'de, W>,
536 }
537
538 impl<'de, B, W> CrcModifier<'de, B, W>
539 where
540 B: Flavor<'de>,
541 W: Width,
542 {
543 /// Create a new Crc modifier Flavor.
544 pub fn new(bee: B, digest: Digest<'de, W>) -> Self {
545 Self { flav: bee, digest }
546 }
547 }
548
549 macro_rules! impl_flavor {
550 ($int:ty, $from_bytes:ident, $take_from_bytes:ident) => {
551 impl<'de, B> Flavor<'de> for CrcModifier<'de, B, $int>
552 where
553 B: Flavor<'de>,
554 {
555 type Remainder = B::Remainder;
556 type Source = B::Source;
557
558 #[inline]
559 fn pop(&mut self) -> Result<u8> {
560 match self.flav.pop() {
561 Ok(byte) => {
562 self.digest.update(&[byte]);
563 Ok(byte)
564 }
565 e @ Err(_) => e,
566 }
567 }
568
569 #[inline]
570 fn size_hint(&self) -> Option<usize> {
571 self.flav.size_hint()
572 }
573
574 #[inline]
575 fn try_take_n(&mut self, ct: usize) -> Result<&'de [u8]> {
576 match self.flav.try_take_n(ct) {
577 Ok(bytes) => {
578 self.digest.update(bytes);
579 Ok(bytes)
580 }
581 e @ Err(_) => e,
582 }
583 }
584
585 fn finalize(mut self) -> Result<Self::Remainder> {
586 match self.flav.try_take_n(core::mem::size_of::<$int>()) {
587 Ok(prev_crc_bytes) => match self.flav.finalize() {
588 Ok(remainder) => {
589 let crc = self.digest.finalize();
590 let le_bytes = prev_crc_bytes
591 .try_into()
592 .map_err(|_| Error::DeserializeBadEncoding)?;
593 let prev_crc = <$int>::from_le_bytes(le_bytes);
594 if crc == prev_crc {
595 Ok(remainder)
596 } else {
597 Err(Error::DeserializeBadCrc)
598 }
599 }
600 e @ Err(_) => e,
601 },
602 Err(e) => Err(e),
603 }
604 }
605 }
606
607 /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any)
608 /// of the byte slice is not returned.
609 pub fn $from_bytes<'a, T>(s: &'a [u8], digest: Digest<'a, $int>) -> Result<T>
610 where
611 T: Deserialize<'a>,
612 {
613 let flav = CrcModifier::new(Slice::new(s), digest);
614 let mut deserializer = Deserializer::from_flavor(flav);
615 let r = T::deserialize(&mut deserializer)?;
616 let _ = deserializer.finalize()?;
617 Ok(r)
618 }
619
620 /// Deserialize a message of type `T` from a byte slice with a Crc. The unused portion (if any)
621 /// of the byte slice is returned for further usage
622 pub fn $take_from_bytes<'a, T>(
623 s: &'a [u8],
624 digest: Digest<'a, $int>,
625 ) -> Result<(T, &'a [u8])>
626 where
627 T: Deserialize<'a>,
628 {
629 let flav = CrcModifier::new(Slice::new(s), digest);
630 let mut deserializer = Deserializer::from_flavor(flav);
631 let t = T::deserialize(&mut deserializer)?;
632 Ok((t, deserializer.finalize()?))
633 }
634 };
635 }
636
637 impl_flavor!(u8, from_bytes_u8, take_from_bytes_u8);
638 impl_flavor!(u16, from_bytes_u16, take_from_bytes_u16);
639 impl_flavor!(u32, from_bytes_u32, take_from_bytes_u32);
640 impl_flavor!(u64, from_bytes_u64, take_from_bytes_u64);
641 impl_flavor!(u128, from_bytes_u128, take_from_bytes_u128);
642}