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("Packet did not have a valid header sequence.")]
45    InvalidHeader,
46
47    #[error("String ran past expected null terminator.")]
48    UnterminatedString,
49
50    #[error(transparent)]
51    Utf8Error(#[from] Utf8Error),
52}
53
54impl<T: Decode> DecodeWithLength for Vec<T> {
55    fn decode_with_len(data: &mut &[u8], len: usize) -> Result<Self, DecodeError> {
56        let mut vec = Vec::with_capacity(len);
57        for _ in 0..len {
58            vec.push(T::decode(data)?);
59        }
60        Ok(vec)
61    }
62}
63
64/// A type that can be reconstructed (decoded) from a raw sequence of bytes.
65///
66/// Implementors of this trait define how to parse their binary representation
67/// from an input buffer. The input slice will be advanced by the number of bytes
68/// successfully consumed during decoding.
69pub trait Decode {
70    /// Attempts to decode `Self` from the beginning of the provided byte slice.
71    ///
72    /// On success, returns the decoded value and advances `data` by the number
73    /// of bytes consumed. On failure, returns a [`DecodeError`].
74    ///
75    /// # Errors
76    ///
77    /// Returns a [`DecodeError`] if the input is malformed or insufficient
78    /// to decode a complete value of this type.
79    fn decode(data: &mut &[u8]) -> Result<Self, DecodeError>
80    where
81        Self: Sized;
82}
83
84/// A type that can be decoded from a sequence of bytes, given an indicator of
85/// the number of items contained within the type.
86///
87/// This is primarily intended for collection-like types (e.g. [`Vec`]) whose
88/// number of elements must be known before decoding can proceed. The caller
89/// provides `len` as the number of items expected to be decoded.
90///
91/// Like [`Decode`], the input slice will be advanced by the number of bytes
92/// successfully consumed.
93pub trait DecodeWithLength {
94    /// Attempts to decode `Self` from the provided byte slice, consuming exactly
95    /// `len` items.
96    ///
97    /// On success, returns the decoded value and advances `data` by the number
98    /// of bytes consumed. On failure, returns a [`DecodeError`].
99    ///
100    /// # Errors
101    ///
102    /// Returns a [`DecodeError`] if the input is malformed or insufficient
103    /// to decode a complete value of this type.
104    fn decode_with_len(data: &mut &[u8], len: usize) -> Result<Self, DecodeError>
105    where
106        Self: Sized;
107}
108
109impl Decode for () {
110    fn decode(_data: &mut &[u8]) -> Result<Self, DecodeError> {
111        Ok(())
112    }
113}
114
115macro_rules! impl_decode_for_primitive {
116    ($($t:ty),*) => {
117        $(
118            impl Decode for $t {
119                fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
120                    let bytes = data.get(..size_of::<Self>()).ok_or_else(|| DecodeError::new::<Self>(DecodeErrorKind::UnexpectedEnd))?;
121                    *data = &data[size_of::<Self>()..];
122                    Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
123                }
124            }
125        )*
126    };
127}
128
129impl_decode_for_primitive!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
130
131// TODO: Switch to try_from_fn and/or array::try_map once stabilized
132impl<const N: usize, T: Decode> Decode for [T; N] {
133    fn decode(data: &mut &[u8]) -> Result<Self, DecodeError> {
134        let mut arr: [MaybeUninit<T>; N] = unsafe { MaybeUninit::uninit().assume_init() };
135
136        for i in 0..N {
137            arr[i] = MaybeUninit::new(T::decode(data)?);
138        }
139
140        Ok(unsafe { core::mem::transmute_copy::<_, [T; N]>(&arr) })
141    }
142}