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
39pub trait Decode {
45 fn decode(data: &mut &[u8]) -> Result<Self, DecodeError>
55 where
56 Self: Sized;
57}
58
59pub trait DecodeWithLength {
69 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
106impl<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}