Skip to main content

cu29_runtime/
payload.rs

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