Skip to main content

fluentbase_codec/
vec.rs

1use crate::{
2    alloc::string::ToString,
3    bytes_codec::{read_bytes, read_bytes_header, write_bytes_solidity, write_bytes_wasm},
4    encoder::{align_up, read_u32_aligned, write_u32_aligned, Encoder},
5    error::{CodecError, DecodingError},
6};
7use alloc::vec::Vec;
8use byteorder::ByteOrder;
9use bytes::{Buf, BytesMut};
10
11/// We encode dynamic arrays as following:
12/// - header
13///   - length: number of elements inside vector
14///   - offset: offset inside structure
15///   - size: number of encoded bytes
16/// - body
17///   - raw bytes of the vector
18///
19/// For Solidity, we don't have size:
20/// - header
21///   - offset
22/// - body
23///   - length
24///   - raw bytes of the vector
25///
26/// Implementation for non-Solidity mode
27impl<T, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, false, false> for Vec<T>
28where
29    T: Default + Sized + Encoder<B, ALIGN, false, false> + alloc::fmt::Debug,
30{
31    const HEADER_SIZE: usize = core::mem::size_of::<u32>() * 3;
32    const IS_DYNAMIC: bool = true;
33
34    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
35        let aligned_elem_size = align_up::<ALIGN>(4);
36        let aligned_header_size = aligned_elem_size * 3;
37
38        // Ensure buffer can store header
39        if buf.len() < offset + aligned_header_size {
40            buf.resize(offset + aligned_header_size, 0);
41        }
42
43        // Write length of the vector
44        write_u32_aligned::<B, ALIGN>(buf, offset, self.len() as u32);
45
46        if self.is_empty() {
47            // Write offset and size for empty vector
48            write_u32_aligned::<B, ALIGN>(
49                buf,
50                offset + aligned_elem_size,
51                aligned_header_size as u32,
52            );
53            write_u32_aligned::<B, ALIGN>(buf, offset + aligned_elem_size * 2, 0);
54            return Ok(());
55        }
56
57        // Encode values
58        let mut value_encoder = BytesMut::zeroed(ALIGN.max(T::HEADER_SIZE) * self.len());
59        for (index, obj) in self.iter().enumerate() {
60            let elem_offset = ALIGN.max(T::HEADER_SIZE) * index;
61            obj.encode(&mut value_encoder, elem_offset)?;
62        }
63
64        let data = value_encoder.freeze();
65        write_bytes_wasm::<B, ALIGN>(buf, offset + aligned_elem_size, &data);
66
67        Ok(())
68    }
69
70    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
71        let aligned_header_el_size = align_up::<ALIGN>(4);
72
73        if buf.remaining() < offset + aligned_header_el_size {
74            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
75                expected: offset + aligned_header_el_size,
76                found: buf.remaining(),
77                msg: "failed to decode vector length".to_string(),
78            }));
79        }
80
81        let data_len = read_u32_aligned::<B, ALIGN>(buf, offset)? as usize;
82        if data_len == 0 {
83            return Ok(Vec::new());
84        }
85
86        let mut result = Vec::with_capacity(data_len);
87        let data = read_bytes::<B, ALIGN, false>(buf, offset + aligned_header_el_size)?;
88
89        for i in 0..data_len {
90            let elem_offset = i * align_up::<ALIGN>(T::HEADER_SIZE);
91            let value = T::decode(&data, elem_offset)?;
92            result.push(value);
93        }
94
95        Ok(result)
96    }
97
98    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
99        read_bytes_header::<B, ALIGN, false>(buf, offset)
100    }
101}
102
103// Implementation for Solidity mode
104impl<T, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, true, false> for Vec<T>
105where
106    T: Default + Sized + Encoder<B, ALIGN, true, false> + alloc::fmt::Debug,
107{
108    const HEADER_SIZE: usize = 32;
109    const IS_DYNAMIC: bool = true;
110
111    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
112        // Ensure buffer can store header
113        if buf.len() < offset + Self::HEADER_SIZE {
114            buf.resize(offset + Self::HEADER_SIZE, 0);
115        }
116
117        // Write offset
118        write_u32_aligned::<B, ALIGN>(buf, offset, buf.len() as u32);
119
120        if self.is_empty() {
121            // Write length for empty vector
122            write_u32_aligned::<B, ALIGN>(buf, buf.len(), 0);
123            return Ok(());
124        }
125
126        // Encode values
127        let mut value_encoder = BytesMut::zeroed(32 * self.len());
128        for (index, obj) in self.iter().enumerate() {
129            let elem_offset = ALIGN.max(T::HEADER_SIZE) * index;
130            obj.encode(&mut value_encoder, elem_offset)?;
131        }
132
133        let data = value_encoder.freeze();
134        write_bytes_solidity::<B, ALIGN>(buf, offset + Self::HEADER_SIZE, &data, self.len() as u32);
135
136        Ok(())
137    }
138
139    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
140        let data_offset = read_u32_aligned::<B, ALIGN>(buf, offset)?;
141        let data_len = read_u32_aligned::<B, ALIGN>(buf, data_offset as usize)? as usize;
142
143        if data_len == 0 {
144            return Ok(Vec::new());
145        }
146
147        let mut result = Vec::with_capacity(data_len);
148        let chunk = &buf.chunk()[(data_offset + 32) as usize..];
149
150        for i in 0..data_len {
151            let elem_offset = i * align_up::<ALIGN>(T::HEADER_SIZE);
152            let value = T::decode(&chunk, elem_offset)?;
153            result.push(value);
154        }
155
156        Ok(result)
157    }
158
159    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
160        read_bytes_header::<B, ALIGN, true>(buf, offset)
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167    use byteorder::{BigEndian, LittleEndian};
168    use bytes::{Bytes, BytesMut};
169
170    #[test]
171    fn test_empty_vec_u32() {
172        let original: Vec<u32> = Vec::new();
173        let mut buf = BytesMut::new();
174
175        <Vec<u32> as Encoder<LittleEndian, 4, false, false>>::encode(&original, &mut buf, 0)
176            .unwrap();
177        let encoded = buf.freeze();
178        let expected = hex::decode("000000000c00000000000000").expect("Failed to decode hex");
179        assert_eq!(encoded, Bytes::from(expected));
180
181        let decoded =
182            <Vec<u32> as Encoder<LittleEndian, 4, false, false>>::decode(&encoded, 0).unwrap();
183
184        assert_eq!(original, decoded);
185    }
186
187    #[test]
188    fn test_vec_u32_simple() {
189        let original: Vec<u32> = vec![1, 2, 3, 4, 5];
190        let mut buf = BytesMut::new();
191
192        <Vec<u32> as Encoder<BigEndian, 4, false, false>>::encode(&original, &mut buf, 0).unwrap();
193        let encoded = buf.freeze();
194
195        let expected_encoded = "000000050000000c000000140000000100000002000000030000000400000005";
196        assert_eq!(hex::encode(&encoded), expected_encoded);
197
198        let decoded =
199            <Vec<u32> as Encoder<BigEndian, 4, false, false>>::decode(&encoded, 0).unwrap();
200
201        assert_eq!(original, decoded);
202    }
203
204    #[test]
205    fn test_vec_u32_with_offset() {
206        let original: Vec<u32> = vec![1, 2, 3, 4, 5];
207        let mut buf = BytesMut::new();
208        buf.extend_from_slice(&[0xFF, 0xFF, 0xFF]); // Add some initial data
209
210        <Vec<u32> as Encoder<LittleEndian, 4, false, false>>::encode(&original, &mut buf, 3)
211            .unwrap();
212        let encoded = buf.freeze();
213
214        let decoded =
215            <Vec<u32> as Encoder<LittleEndian, 4, false, false>>::decode(&encoded, 3).unwrap();
216
217        assert_eq!(original, decoded);
218    }
219
220    #[test]
221    fn test_vec_u8_with_offset() {
222        let original: Vec<u8> = vec![1, 2, 3, 4, 5];
223        let mut buf = BytesMut::new();
224        buf.extend_from_slice(&[0xFF, 0xFF, 0xFF]); // Add some initial data
225
226        <Vec<u8> as Encoder<LittleEndian, 4, false, false>>::encode(&original, &mut buf, 3)
227            .unwrap();
228        let encoded = buf.freeze();
229
230        let decoded =
231            <Vec<u8> as Encoder<LittleEndian, 4, false, false>>::decode(&encoded, 3).unwrap();
232
233        assert_eq!(original, decoded);
234    }
235
236    #[test]
237    fn test_nested_vec_le_a2() {
238        let original: Vec<Vec<u16>> = vec![vec![3, 4], vec![5, 6, 7]];
239
240        let mut buf = BytesMut::new();
241        <Vec<Vec<u16>> as Encoder<LittleEndian, 2, false, false>>::encode(&original, &mut buf, 0)
242            .unwrap();
243        let encoded = buf.freeze();
244
245        let expected_encoded = "020000000c00000022000000020000001800000004000000030000001c0000000600000003000400050006000700";
246
247        assert_eq!(hex::encode(&encoded), expected_encoded);
248
249        let decoded =
250            <Vec<Vec<u16>> as Encoder<LittleEndian, 2, false, false>>::decode(&encoded, 0).unwrap();
251
252        assert_eq!(original, decoded);
253    }
254
255    #[test]
256    fn test_nested_vec_a4_le() {
257        let original: Vec<Vec<u16>> = vec![vec![3, 4], vec![5, 6, 7]];
258
259        let mut buf = BytesMut::new();
260        <Vec<Vec<u16>> as Encoder<LittleEndian, 4, false, false>>::encode(&original, &mut buf, 0)
261            .unwrap();
262        let encoded = buf.freeze();
263        let decoded =
264            <Vec<Vec<u16>> as Encoder<LittleEndian, 4, false, false>>::decode(&encoded, 0).unwrap();
265
266        assert_eq!(original, decoded);
267    }
268
269    #[test]
270    fn test_nested_vec_a4_be() {
271        let original: Vec<Vec<u16>> = vec![vec![3, 4], vec![5, 6, 7]];
272
273        let mut buf = BytesMut::new();
274        <Vec<Vec<u16>> as Encoder<BigEndian, 4, false, false>>::encode(&original, &mut buf, 0)
275            .unwrap();
276        let encoded = buf.freeze();
277
278        let decoded =
279            <Vec<Vec<u16>> as Encoder<BigEndian, 4, false, false>>::decode(&encoded, 0).unwrap();
280
281        assert_eq!(original, decoded);
282    }
283
284    #[test]
285    fn test_large_vec() {
286        let original: Vec<u64> = (0..1000).collect();
287        let mut buf = BytesMut::new();
288
289        <Vec<u64> as Encoder<BigEndian, 8, false, false>>::encode(&original, &mut buf, 0).unwrap();
290        let encoded = buf.freeze();
291
292        let decoded =
293            <Vec<u64> as Encoder<BigEndian, 8, false, false>>::decode(&encoded, 0).unwrap();
294
295        assert_eq!(original, decoded);
296    }
297
298    // New test for Solidity mode
299    #[test]
300    fn test_vec_u32_solidity_mode() {
301        let original: Vec<u32> = vec![1, 2, 3, 4, 5];
302        let mut buf = BytesMut::new();
303
304        <Vec<u32> as Encoder<BigEndian, 32, true, false>>::encode(&original, &mut buf, 0).unwrap();
305        let encoded = buf.freeze();
306
307        let decoded =
308            <Vec<u32> as Encoder<BigEndian, 32, true, false>>::decode(&encoded, 0).unwrap();
309
310        assert_eq!(original, decoded);
311    }
312}