vex_cdc/
decode.rs

1use alloc::vec::Vec;
2use core::{mem::MaybeUninit, str::Utf8Error};
3use thiserror::Error;
4
5#[derive(Debug, Error, PartialEq, Eq)]
6pub struct DecodeError {
7    kind: DecodeErrorKind,
8    type_name: &'static str,
9}
10
11impl DecodeError {
12    pub fn new<T>(kind: DecodeErrorKind) -> Self {
13        Self {
14            kind,
15            type_name: core::any::type_name::<T>(),
16        }
17    }
18
19    pub const fn kind(&self) -> DecodeErrorKind {
20        self.kind
21    }
22}
23
24impl core::fmt::Display for DecodeError {
25    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
26        write!(f, "Failed to decode {}: {}", self.type_name, self.kind)
27    }
28}
29
30#[derive(Error, Clone, Copy, Debug, PartialEq, Eq)]
31pub enum DecodeErrorKind {
32    #[error("Packet was too short.")]
33    UnexpectedEnd,
34
35    #[error(
36        "Could not decode {name} with unexpected byte. Found {value:x}, expected one of: {expected:x?}."
37    )]
38    UnexpectedByte {
39        name: &'static str,
40        value: u8,
41        expected: &'static [u8],
42    },
43
44    #[error("CRC16 checksum mismatch. Found {value:x}, expected {expected:x}.")]
45    Checksum { value: u16, expected: u16 },
46
47    #[error("Packet did not have a valid header sequence.")]
48    InvalidHeader,
49
50    #[error("String ran past expected null terminator.")]
51    UnterminatedString,
52
53    #[error(transparent)]
54    Utf8Error(#[from] Utf8Error),
55}
56
57impl<T: Decode> DecodeWithLength for Vec<T> {
58    fn decode_with_len(data: &mut &[u8], len: usize) -> Result<Self, DecodeError> {
59        let mut vec = Vec::with_capacity(len);
60        for _ in 0..len {
61            vec.push(T::decode(data)?);
62        }
63        Ok(vec)
64    }
65}
66
67/// A type that can be reconstructed (decoded) from a raw sequence of bytes.
68///
69/// Implementors of this trait define how to parse their binary representation
70/// from an input buffer. The input slice will be advanced by the number of bytes
71/// successfully consumed during decoding.
72pub trait Decode {
73    /// Attempts to decode `Self` from the beginning of the provided byte slice.
74    ///
75    /// On success, returns the decoded value and advances `data` by the number
76    /// of bytes consumed. On failure, returns a [`DecodeError`].
77    ///
78    /// # Errors
79    ///
80    /// Returns a [`DecodeError`] if the input is malformed or insufficient
81    /// to decode a complete value of this type.
82    fn decode(data: &mut &[u8]) -> Result<Self, DecodeError>
83    where
84        Self: Sized;
85}
86
87/// A type that can be decoded from a sequence of bytes, given an indicator of
88/// the number of items contained within the type.
89///
90/// This is primarily intended for collection-like types (e.g. [`Vec`]) whose
91/// number of elements must be known before decoding can proceed. The caller
92/// provides `len` as the number of items expected to be decoded.
93///
94/// Like [`Decode`], the input slice will be advanced by the number of bytes
95/// successfully consumed.
96pub trait DecodeWithLength {
97    /// Attempts to decode `Self` from the provided byte slice, consuming exactly
98    /// `len` items.
99    ///
100    /// On success, returns the decoded value and advances `data` by the number
101    /// of bytes consumed. On failure, returns a [`DecodeError`].
102    ///
103    /// # Errors
104    ///
105    /// Returns a [`DecodeError`] if the input is malformed or insufficient
106    /// to decode a complete value of this type.
107    fn decode_with_len(data: &mut &[u8], len: usize) -> Result<Self, DecodeError>
108    where
109        Self: Sized;
110}
111
112impl Decode for () {
113    fn decode(_data: &mut &[u8]) -> Result<Self, DecodeError> {
114        Ok(())
115    }
116}
117
118macro_rules! impl_decode_for_primitive {
119    ($($t:ty),*) => {
120        $(
121            impl Decode for $t {
122                fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
123                    let bytes = data.get(..size_of::<Self>()).ok_or_else(|| DecodeError::new::<Self>(DecodeErrorKind::UnexpectedEnd))?;
124                    *data = &data[size_of::<Self>()..];
125                    Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
126                }
127            }
128        )*
129    };
130}
131
132impl_decode_for_primitive!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
133
134// TODO: Switch to try_from_fn and/or array::try_map once stabilized
135impl<const N: usize, T: Decode> Decode for [T; N] {
136    fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
137        let mut arr: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
138
139        for i in 0..N {
140            arr[i] = MaybeUninit::new(T::decode(data)?);
141        }
142
143        Ok(unsafe { core::mem::transmute_copy::<_, [T; N]>(&arr) })
144    }
145}