cu29_runtime/
payload.rs

1/// This module is a collection of Copper friendly data structures for message payloads.
2///
3/// The constraint on the messages is that they can be part of a copper list, fixed sized and bincode serializable.
4use arrayvec::ArrayVec;
5use bincode::de::{BorrowDecoder, Decoder};
6use bincode::enc::Encoder;
7use bincode::error::{DecodeError, EncodeError};
8use bincode::BorrowDecode;
9use bincode::{Decode, Encode};
10
11/// Copper friendly wrapper for a fixed size array.
12#[derive(Clone, Debug, Default)]
13pub struct CuArray<T, const N: usize> {
14    inner: ArrayVec<T, N>,
15}
16
17impl<T, const N: usize> CuArray<T, N> {
18    pub fn new() -> Self {
19        Self {
20            inner: ArrayVec::new(),
21        }
22    }
23
24    pub fn fill_from_iter<I>(&mut self, iter: I)
25    where
26        I: IntoIterator<Item = T>,
27    {
28        self.inner.clear(); // Clear existing data
29        for value in iter.into_iter().take(N) {
30            self.inner.push(value);
31        }
32    }
33
34    pub fn len(&self) -> usize {
35        self.inner.len()
36    }
37
38    pub fn is_empty(&self) -> bool {
39        self.inner.len() == 0
40    }
41
42    pub fn as_slice(&self) -> &[T] {
43        &self.inner
44    }
45
46    pub fn capacity(&self) -> usize {
47        N
48    }
49}
50
51impl<T, const N: usize> Encode for CuArray<T, N>
52where
53    T: Encode,
54{
55    fn encode<E: bincode::enc::Encoder>(
56        &self,
57        encoder: &mut E,
58    ) -> Result<(), bincode::error::EncodeError> {
59        // Encode the length first
60        (self.inner.len() as u32).encode(encoder)?;
61
62        // Encode elements in the `ArrayVec`
63        for elem in &self.inner {
64            elem.encode(encoder)?;
65        }
66
67        Ok(())
68    }
69}
70
71impl<T, const N: usize> Decode<()> for CuArray<T, N>
72where
73    T: Decode<()>,
74{
75    fn decode<D: bincode::de::Decoder<Context = ()>>(
76        decoder: &mut D,
77    ) -> Result<Self, bincode::error::DecodeError> {
78        // Decode the length first
79        let len = u32::decode(decoder)? as usize;
80        if len > N {
81            return Err(bincode::error::DecodeError::OtherString(format!(
82                "Decoded length {len} exceeds maximum capacity {N}"
83            )));
84        }
85
86        // Decode elements into a new `ArrayVec`
87        let mut inner = ArrayVec::new();
88        for _ in 0..len {
89            inner.push(T::decode(decoder)?);
90        }
91
92        Ok(Self { inner })
93    }
94}
95
96/// A Copper-friendly wrapper around ArrayVec with bincode serialization support.
97///
98/// This provides a fixed-capacity, stack-allocated vector that can be efficiently
99/// serialized and deserialized. It is particularly useful for message payloads that
100/// need to avoid heap allocations while supporting varying lengths of data up to a maximum.
101///
102/// Unlike standard Vec, CuArrayVec will never reallocate or use the heap for the elements storage.
103#[derive(Debug, Clone)]
104pub struct CuArrayVec<T, const N: usize>(pub ArrayVec<T, N>);
105
106impl<T, const N: usize> Default for CuArrayVec<T, N> {
107    fn default() -> Self {
108        Self(ArrayVec::new())
109    }
110}
111
112impl<T, const N: usize> Encode for CuArrayVec<T, N>
113where
114    T: Encode + 'static,
115{
116    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
117        let CuArrayVec(inner) = self;
118        inner.as_slice().encode(encoder)
119    }
120}
121
122impl<T, const N: usize> Decode<()> for CuArrayVec<T, N>
123where
124    T: Decode<()> + 'static,
125{
126    fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
127        let inner = Vec::<T>::decode(decoder)?;
128        let actual_len = inner.len();
129        if actual_len > N {
130            return Err(DecodeError::ArrayLengthMismatch {
131                required: N,
132                found: actual_len,
133            });
134        }
135
136        let mut array_vec = ArrayVec::new();
137        for item in inner {
138            array_vec.push(item); // Push elements one by one
139        }
140        Ok(CuArrayVec(array_vec))
141    }
142}
143
144impl<'de, T, const N: usize> BorrowDecode<'de, ()> for CuArrayVec<T, N>
145where
146    T: BorrowDecode<'de, ()> + 'static,
147{
148    fn borrow_decode<D: BorrowDecoder<'de, Context = ()>>(
149        decoder: &mut D,
150    ) -> Result<Self, DecodeError> {
151        let inner = Vec::<T>::borrow_decode(decoder)?;
152        let actual_len = inner.len();
153        if actual_len > N {
154            return Err(DecodeError::ArrayLengthMismatch {
155                required: N,
156                found: actual_len,
157            });
158        }
159
160        let mut array_vec = ArrayVec::new();
161        for item in inner {
162            array_vec.push(item); // Push elements one by one
163        }
164        Ok(CuArrayVec(array_vec))
165    }
166}