vex_cdc/
encode.rs

1/// Simplifies encoding data with the [`Encode`] trait.
2///
3/// `MessageEncoder` maintains an internal position within a mutable byte slice akin to
4/// std's `Cursor` type, allowing sequential writing of multiple encoded values without
5/// manually tracking offsets.
6///
7/// # Example
8/// 
9/// ```
10/// let mut buf = [0u8; 16];
11/// let mut enc = MessageEncoder::new(&mut buf);
12/// let value: u16 = 0x1234;
13/// enc.write(&value);
14/// assert_eq!(enc.position(), 2);
15/// ```
16pub struct MessageEncoder<'a> {
17    data: &'a mut [u8],
18    pos: usize,
19}
20
21impl<'a> MessageEncoder<'a> {
22    /// Creates a new encoder starting at position 0.
23    pub const fn new(data: &'a mut [u8]) -> Self {
24        Self { data, pos: 0 }
25    }
26
27    /// Creates a new encoder starting at the given `pos`.
28    pub const fn new_with_position(data: &'a mut [u8], pos: usize) -> Self {
29        Self { data, pos }
30    }
31
32    /// Encodes a value implementing [`Encode`] into the underlying buffer,
33    /// advancing the current position by `value.size()`.
34    pub fn write<T: Encode>(&mut self, value: &T) {
35        let data = &mut self.data[self.pos..];
36
37        value.encode(data);
38        self.pos += value.size();
39    }
40
41    /// Sets the current write position.
42    #[inline]
43    pub const fn set_position(&mut self, pos: usize) {
44        self.pos = pos;
45    }
46
47    /// Returns the current write position.
48    #[inline]
49    #[must_use]
50    pub const fn position(&self) -> usize {
51        self.pos
52    }
53
54    /// Returns a reference to the underlying buffer.
55    #[inline]
56    #[must_use]
57    pub const fn get_ref(&self) -> &[u8] {
58        self.data
59    }
60}
61
62/// A type that can be encoded into a sequence of bytes.
63pub trait Encode {
64    /// Returns the number of bytes this value will take when encoded.
65    fn size(&self) -> usize;
66
67    /// Encodes this instance into the provided byte slice.
68    fn encode(&self, data: &mut [u8]);
69}
70
71macro_rules! impl_encode_for_primitive {
72    ($($t:ty),*) => {
73        $(
74            impl Encode for $t {
75                fn size(&self) -> usize {
76                    size_of::<Self>()
77                }
78
79                fn encode(&self, data: &mut [u8]) {
80                    data[..size_of::<Self>()].copy_from_slice(&self.to_le_bytes());
81                }
82            }
83        )*
84    };
85}
86
87impl_encode_for_primitive!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128);
88
89impl Encode for () {
90    fn size(&self) -> usize {
91        0
92    }
93    fn encode(&self, _data: &mut [u8]) {}
94}
95
96impl Encode for &[u8] {
97    fn size(&self) -> usize {
98        self.len()
99    }
100
101    fn encode(&self, data: &mut [u8]) {
102        data[..self.len()].copy_from_slice(self);
103    }
104}
105
106impl<const N: usize> Encode for [u8; N] {
107    fn size(&self) -> usize {
108        N
109    }
110
111    fn encode(&self, data: &mut [u8]) {
112        data[..N].copy_from_slice(self);
113    }
114}
115
116impl Encode for alloc::vec::Vec<u8> {
117    fn size(&self) -> usize {
118        self.len()
119    }
120
121    fn encode(&self, data: &mut [u8]) {
122        self.as_slice().encode(data)
123    }
124}