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#[cfg(not(feature = "std"))]
13pub use alloc::format;
14#[cfg(not(feature = "std"))]
15pub use alloc::vec::Vec;
16
17/// Copper friendly wrapper for a fixed size array.
18#[derive(Clone, Debug, Default, Serialize, Deserialize)]
19pub struct CuArray<T, const N: usize> {
20    inner: ArrayVec<T, N>,
21}
22
23impl<T, const N: usize> CuArray<T, N> {
24    pub fn new() -> Self {
25        Self {
26            inner: ArrayVec::new(),
27        }
28    }
29
30    pub fn fill_from_iter<I>(&mut self, iter: I)
31    where
32        I: IntoIterator<Item = T>,
33    {
34        self.inner.clear(); // Clear existing data
35        for value in iter.into_iter().take(N) {
36            self.inner.push(value);
37        }
38    }
39
40    pub fn len(&self) -> usize {
41        self.inner.len()
42    }
43
44    pub fn is_empty(&self) -> bool {
45        self.inner.len() == 0
46    }
47
48    pub fn as_slice(&self) -> &[T] {
49        &self.inner
50    }
51
52    pub fn capacity(&self) -> usize {
53        N
54    }
55}
56
57impl<T, const N: usize> Encode for CuArray<T, N>
58where
59    T: Encode,
60{
61    fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
62        // Encode the length first
63        (self.inner.len() as u32).encode(encoder)?;
64
65        // Encode elements in the `ArrayVec`
66        for elem in &self.inner {
67            elem.encode(encoder)?;
68        }
69
70        Ok(())
71    }
72}
73
74impl<T, const N: usize> Decode<()> for CuArray<T, N>
75where
76    T: Decode<()>,
77{
78    fn decode<D: Decoder<Context = ()>>(decoder: &mut D) -> Result<Self, DecodeError> {
79        // Decode the length first
80        let len = u32::decode(decoder)? as usize;
81        if len > N {
82            return Err(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}