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