vex_cdc/
decode.rs

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