Skip to main content

fluentbase_codec/
hash.rs

1use crate::{
2    bytes_codec::{read_bytes_header, write_bytes, write_bytes_solidity, write_bytes_wasm},
3    encoder::{align_up, read_u32_aligned, write_u32_aligned, Encoder},
4    error::{CodecError, DecodingError},
5};
6use alloc::{format, string::ToString, vec::Vec};
7use byteorder::ByteOrder;
8use bytes::{Buf, BytesMut};
9use core::{fmt::Debug, hash::Hash};
10use hashbrown::{HashMap, HashSet};
11
12/// Implement encoding for HashMap, SOL_MODE = false
13impl<K, V, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, false, false> for HashMap<K, V>
14where
15    K: Default + Sized + Encoder<B, ALIGN, false, false> + Eq + Hash + Ord,
16    V: Default + Sized + Encoder<B, ALIGN, false, false>,
17{
18    const HEADER_SIZE: usize = 4 + 8 + 8; // length + keys_header + values_header
19    const IS_DYNAMIC: bool = true;
20
21    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
22        let aligned_header_el_size = align_up::<ALIGN>(4);
23        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
24
25        // Ensure buf is large enough for the header
26        if buf.len() < offset + aligned_header_size {
27            buf.resize(offset + aligned_header_size, 0);
28        }
29
30        // Write map size
31        write_u32_aligned::<B, ALIGN>(buf, offset, self.len() as u32);
32
33        // Make sure keys & values are sorted
34        let mut entries: Vec<_> = self.iter().collect();
35        entries.sort_by(|a, b| a.0.cmp(b.0));
36
37        // Encode and write keys
38        let mut key_buf = BytesMut::zeroed(align_up::<ALIGN>(K::HEADER_SIZE) * self.len());
39
40        for (i, (key, _)) in entries.iter().enumerate() {
41            let key_offset = align_up::<ALIGN>(K::HEADER_SIZE) * i;
42            key.encode(&mut key_buf, key_offset)?;
43        }
44
45        // write keys header and keys data
46        write_bytes::<B, ALIGN, false>(
47            buf,
48            offset + aligned_header_el_size,
49            &key_buf,
50            entries.len() as u32,
51        );
52
53        // Encode and write values
54        let mut value_buf = BytesMut::zeroed(align_up::<ALIGN>(V::HEADER_SIZE) * self.len());
55        for (i, (_, value)) in entries.iter().enumerate() {
56            let value_offset = align_up::<ALIGN>(V::HEADER_SIZE) * i;
57            value.encode(&mut value_buf, value_offset)?;
58        }
59
60        write_bytes_wasm::<B, ALIGN>(buf, offset + aligned_header_el_size * 3, &value_buf);
61
62        Ok(())
63    }
64
65    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
66        let aligned_header_el_size = align_up::<ALIGN>(4);
67        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
68
69        if buf.remaining() < offset + aligned_header_size {
70            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
71                expected: offset + aligned_header_size,
72                found: buf.remaining(),
73                msg: "Not enough data to decode HashMap header".to_string(),
74            }));
75        }
76
77        let length = read_u32_aligned::<B, ALIGN>(buf, offset)? as usize;
78
79        let (keys_offset, keys_length) =
80            read_bytes_header::<B, ALIGN, false>(buf, offset + aligned_header_el_size)?;
81
82        let (values_offset, values_length) =
83            read_bytes_header::<B, ALIGN, false>(buf, offset + aligned_header_el_size * 3)?;
84
85        let key_bytes = &buf.chunk()[keys_offset..keys_offset + keys_length];
86        let value_bytes = &buf.chunk()[values_offset..values_offset + values_length];
87
88        let keys = (0..length).map(|i| {
89            let key_offset = align_up::<ALIGN>(K::HEADER_SIZE) * i;
90            K::decode(&key_bytes, key_offset).unwrap_or_default()
91        });
92
93        let values = (0..length).map(|i| {
94            let value_offset = align_up::<ALIGN>(V::HEADER_SIZE) * i;
95            V::decode(&value_bytes, value_offset).unwrap_or_default()
96        });
97
98        let result: HashMap<K, V> = keys.zip(values).collect();
99
100        if result.len() != length {
101            return Err(CodecError::Decoding(DecodingError::InvalidData(format!(
102                "Expected {} elements, but decoded {}",
103                length,
104                result.len()
105            ))));
106        }
107
108        Ok(result)
109    }
110
111    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
112        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
113
114        if buf.remaining() < offset + aligned_header_size {
115            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
116                expected: offset + aligned_header_size,
117                found: buf.remaining(),
118                msg: "Not enough data to decode HashMap header".to_string(),
119            }));
120        }
121
122        let (keys_offset, keys_length) =
123            read_bytes_header::<B, ALIGN, false>(buf, offset + align_up::<ALIGN>(4))?;
124        let (_values_offset, values_length) =
125            read_bytes_header::<B, ALIGN, false>(buf, offset + align_up::<ALIGN>(12))?;
126
127        Ok((keys_offset, keys_length + values_length))
128    }
129}
130/// Implement encoding for HashMap, SOL_MODE = true
131impl<K, V, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, true, false> for HashMap<K, V>
132where
133    K: Debug + Default + Sized + Encoder<B, ALIGN, true, false> + Eq + Hash + Ord,
134    V: Debug + Default + Sized + Encoder<B, ALIGN, true, false>,
135{
136    const HEADER_SIZE: usize = 32 + 32 + 32 + 32; // offset + length + keys_header + values_header
137
138    const IS_DYNAMIC: bool = true;
139
140    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
141        // Ensure buf is large enough for the header
142        if buf.len() < offset + Self::HEADER_SIZE {
143            buf.resize(offset + Self::HEADER_SIZE, 0);
144        }
145
146        // Write offset size
147        write_u32_aligned::<B, ALIGN>(buf, offset, 32_u32);
148
149        // Write map size
150        write_u32_aligned::<B, ALIGN>(buf, offset + 32, self.len() as u32);
151
152        // Make sure keys & values are sorted
153        let mut entries: Vec<_> = self.iter().collect();
154        entries.sort_by(|a, b| a.0.cmp(b.0));
155
156        // Encode and write keys
157        let mut key_buf = BytesMut::zeroed(align_up::<ALIGN>(K::HEADER_SIZE) * self.len());
158
159        for (i, (key, _)) in entries.iter().enumerate() {
160            let key_offset = align_up::<ALIGN>(K::HEADER_SIZE) * i;
161            key.encode(&mut key_buf, key_offset)?;
162        }
163        let relative_key_offset = buf.len() - offset - 64;
164        // Write key offset
165        write_u32_aligned::<B, ALIGN>(buf, offset + 64, relative_key_offset as u32);
166
167        // write key header and keys data to the buf
168        write_bytes_solidity::<B, ALIGN>(buf, offset + 64, &key_buf, entries.len() as u32);
169
170        // Write values offset
171        let relative_value_offset = buf.len() - offset - 96;
172        write_u32_aligned::<B, ALIGN>(buf, offset + 96, relative_value_offset as u32);
173
174        // Encode and write values
175        let mut value_buf = BytesMut::zeroed(align_up::<ALIGN>(V::HEADER_SIZE) * self.len());
176        for (i, (_, value)) in entries.iter().enumerate() {
177            let value_offset = align_up::<ALIGN>(V::HEADER_SIZE) * i;
178            value.encode(&mut value_buf, value_offset)?;
179        }
180
181        write_bytes_solidity::<B, ALIGN>(buf, buf.len(), &value_buf, entries.len() as u32);
182
183        Ok(())
184    }
185
186    // current solidity decode nested map
187    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
188        const KEYS_OFFSET: usize = 32;
189        const VALUES_OFFSET: usize = 64;
190
191        // Check if there's enough data to read the header
192        let header_end = offset
193            .checked_add(Self::HEADER_SIZE)
194            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
195
196        if buf.remaining() < header_end {
197            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
198                expected: header_end,
199                found: buf.remaining(),
200                msg: "Not enough data to decode HashMap header".to_string(),
201            }));
202        }
203
204        // Read data offset
205        let data_offset = read_u32_aligned::<B, ALIGN>(buf, offset)? as usize;
206
207        // Calculate start offset
208        let start_offset = offset
209            .checked_add(data_offset)
210            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
211
212        // Read length
213        let length = read_u32_aligned::<B, ALIGN>(buf, start_offset)? as usize;
214        if length == 0 {
215            return Ok(HashMap::new());
216        }
217
218        // Read relative keys and values offsets (relative to the current offset)
219        let keys_offset = read_u32_aligned::<B, ALIGN>(buf, start_offset + KEYS_OFFSET)? as usize;
220        let values_offset =
221            read_u32_aligned::<B, ALIGN>(buf, start_offset + VALUES_OFFSET)? as usize;
222
223        // Calculate absolute offsets
224        let keys_start = keys_offset
225            .checked_add(start_offset)
226            .and_then(|sum| sum.checked_add(KEYS_OFFSET))
227            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
228        let values_start = values_offset
229            .checked_add(start_offset)
230            .and_then(|sum| sum.checked_add(VALUES_OFFSET))
231            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
232
233        let mut result = HashMap::with_capacity(length);
234
235        let keys_data = &buf.chunk()[keys_start + 32..];
236        let values_data = &buf.chunk()[values_start + 32..];
237
238        for i in 0..length {
239            let key_offset = align_up::<ALIGN>(K::HEADER_SIZE)
240                .checked_mul(i)
241                .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
242            let value_offset = align_up::<ALIGN>(V::HEADER_SIZE)
243                .checked_mul(i)
244                .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
245
246            let key = K::decode(&keys_data, key_offset)?;
247            let value = V::decode(&values_data, value_offset)?;
248
249            result.insert(key, value);
250        }
251
252        Ok(result)
253    }
254
255    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
256        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
257
258        if buf.remaining() < offset + aligned_header_size {
259            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
260                expected: offset + aligned_header_size,
261                found: buf.remaining(),
262                msg: "Not enough data to decode HashMap header".to_string(),
263            }));
264        }
265
266        let (keys_offset, keys_length) =
267            read_bytes_header::<B, ALIGN, false>(buf, offset + align_up::<ALIGN>(4))?;
268        let (_values_offset, values_length) =
269            read_bytes_header::<B, ALIGN, false>(buf, offset + align_up::<ALIGN>(12))?;
270
271        Ok((keys_offset, keys_length + values_length))
272    }
273}
274
275/// Implement encoding for HashSet, SOL_MODE = false
276impl<T, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, false, false> for HashSet<T>
277where
278    T: Default + Sized + Encoder<B, ALIGN, false, false> + Eq + Hash + Ord,
279{
280    const HEADER_SIZE: usize = 4 + 8; // length + data_header
281    const IS_DYNAMIC: bool = true;
282
283    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
284        let aligned_offset = align_up::<ALIGN>(offset);
285        let aligned_header_el_size = align_up::<ALIGN>(4);
286        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
287
288        // Ensure buf is large enough for the header
289        if buf.len() < aligned_offset + aligned_header_size {
290            buf.resize(aligned_offset + aligned_header_size, 0);
291        }
292
293        // Write set size
294        write_u32_aligned::<B, ALIGN>(buf, aligned_offset, self.len() as u32);
295
296        // Make sure a set is sorted
297        let mut entries: Vec<_> = self.iter().collect();
298        entries.sort();
299
300        // Encode values
301        let mut value_buf = BytesMut::zeroed(align_up::<ALIGN>(T::HEADER_SIZE) * self.len());
302        for (i, value) in entries.iter().enumerate() {
303            let value_offset = align_up::<ALIGN>(T::HEADER_SIZE) * i;
304            value.encode(&mut value_buf, value_offset)?;
305        }
306
307        // Write values
308        write_bytes::<B, ALIGN, false>(
309            buf,
310            aligned_offset + aligned_header_el_size,
311            &value_buf,
312            entries.len() as u32,
313        );
314
315        Ok(())
316    }
317
318    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
319        let aligned_offset = align_up::<ALIGN>(offset);
320        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
321
322        if buf.remaining() < aligned_offset + aligned_header_size {
323            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
324                expected: aligned_offset + aligned_header_size,
325                found: buf.remaining(),
326                msg: "Not enough data to decode HashSet header".to_string(),
327            }));
328        }
329
330        let length = read_u32_aligned::<B, ALIGN>(buf, aligned_offset)? as usize;
331
332        let (data_offset, data_length) =
333            read_bytes_header::<B, ALIGN, false>(buf, aligned_offset + align_up::<ALIGN>(4))?;
334
335        let mut result = HashSet::with_capacity(length);
336
337        let value_bytes = &buf.chunk()[data_offset..data_offset + data_length];
338
339        for i in 0..length {
340            let value_offset = align_up::<ALIGN>(T::HEADER_SIZE) * i;
341            let value = T::decode(&value_bytes, value_offset)?;
342            result.insert(value);
343        }
344
345        if result.len() != length {
346            return Err(CodecError::Decoding(DecodingError::InvalidData(format!(
347                "Expected {} elements, but decoded {}",
348                length,
349                result.len()
350            ))));
351        }
352
353        Ok(result)
354    }
355
356    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
357        let aligned_offset = align_up::<ALIGN>(offset);
358        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
359
360        if buf.remaining() < aligned_offset + aligned_header_size {
361            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
362                expected: aligned_offset + aligned_header_size,
363                found: buf.remaining(),
364                msg: "Not enough data to decode HashSet header".to_string(),
365            }));
366        }
367
368        let (data_offset, data_length) =
369            read_bytes_header::<B, ALIGN, false>(buf, aligned_offset + align_up::<ALIGN>(4))?;
370
371        Ok((data_offset, data_length))
372    }
373}
374
375/// Implement encoding for HashSet, SOL_MODE = true
376impl<T, B: ByteOrder, const ALIGN: usize> Encoder<B, ALIGN, true, false> for HashSet<T>
377where
378    T: Debug + Default + Sized + Encoder<B, ALIGN, true, false> + Eq + Hash + Ord,
379{
380    const HEADER_SIZE: usize = 32 + 32 + 32; // offset + length + data_header
381    const IS_DYNAMIC: bool = true;
382    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
383        let aligned_offset = align_up::<ALIGN>(offset);
384
385        // Ensure buf is large enough for the header
386        if buf.len() < aligned_offset + Self::HEADER_SIZE {
387            buf.resize(aligned_offset + Self::HEADER_SIZE, 0);
388        }
389
390        // Write offset size
391        write_u32_aligned::<B, ALIGN>(buf, aligned_offset, 32_u32);
392
393        // Write set size
394        write_u32_aligned::<B, ALIGN>(buf, aligned_offset + 32, self.len() as u32);
395
396        // Make sure set is sorted
397        let mut entries: Vec<_> = self.iter().collect();
398        entries.sort();
399
400        // Encode values
401        let mut value_buf = BytesMut::zeroed(align_up::<ALIGN>(T::HEADER_SIZE) * self.len());
402        for (i, value) in entries.iter().enumerate() {
403            let value_offset = align_up::<ALIGN>(T::HEADER_SIZE) * i;
404            value.encode(&mut value_buf, value_offset)?;
405        }
406
407        // Write data offset
408        let relative_data_offset = buf.len() - aligned_offset - 64;
409        write_u32_aligned::<B, ALIGN>(buf, aligned_offset + 64, relative_data_offset as u32);
410
411        // Write values
412        write_bytes_solidity::<B, ALIGN>(buf, buf.len(), &value_buf, entries.len() as u32);
413
414        Ok(())
415    }
416
417    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
418        const DATA_OFFSET: usize = 32;
419
420        let aligned_offset = align_up::<ALIGN>(offset);
421
422        // Check if there's enough data to read the header
423        let header_end = aligned_offset
424            .checked_add(Self::HEADER_SIZE)
425            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
426
427        if buf.remaining() < header_end {
428            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
429                expected: header_end,
430                found: buf.remaining(),
431                msg: "Not enough data to decode HashSet header".to_string(),
432            }));
433        }
434
435        // Read data offset
436        let data_offset = read_u32_aligned::<B, ALIGN>(buf, aligned_offset)? as usize;
437
438        // Calculate start offset
439        let start_offset = aligned_offset
440            .checked_add(data_offset)
441            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
442
443        // Read length
444        let length = read_u32_aligned::<B, ALIGN>(buf, start_offset)? as usize;
445        if length == 0 {
446            return Ok(HashSet::new());
447        }
448
449        // Read relative data offset (relative to the current offset)
450        let values_offset = read_u32_aligned::<B, ALIGN>(buf, start_offset + DATA_OFFSET)? as usize;
451
452        // Calculate absolute offset
453        let values_start = values_offset
454            .checked_add(start_offset)
455            .and_then(|sum| sum.checked_add(DATA_OFFSET))
456            .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
457
458        let mut result = HashSet::with_capacity(length);
459
460        let values_data = &buf.chunk()[values_start + 32..];
461
462        for i in 0..length {
463            let value_offset = align_up::<ALIGN>(T::HEADER_SIZE)
464                .checked_mul(i)
465                .ok_or(CodecError::Decoding(DecodingError::Overflow))?;
466
467            let value = T::decode(&values_data, value_offset)?;
468            result.insert(value);
469        }
470
471        Ok(result)
472    }
473
474    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
475        let aligned_offset = align_up::<ALIGN>(offset);
476        let aligned_header_size = align_up::<ALIGN>(Self::HEADER_SIZE);
477
478        if buf.remaining() < aligned_offset + aligned_header_size {
479            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
480                expected: aligned_offset + aligned_header_size,
481                found: buf.remaining(),
482                msg: "Not enough data to decode HashSet header".to_string(),
483            }));
484        }
485
486        let data_offset = read_u32_aligned::<B, ALIGN>(buf, aligned_offset)? as usize;
487        let start_offset = aligned_offset + data_offset;
488        let length = read_u32_aligned::<B, ALIGN>(buf, start_offset)? as usize;
489        let values_offset = read_u32_aligned::<B, ALIGN>(buf, start_offset + 64)? as usize;
490        let values_start = start_offset + 64 + values_offset;
491
492        let data_length = length * align_up::<ALIGN>(T::HEADER_SIZE);
493
494        Ok((values_start + 32, data_length))
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use super::*;
501    use crate::{
502        encoder::{CompactABI, SolidityABI},
503        test_utils::print_bytes,
504    };
505    use alloc::vec::Vec;
506    use byteorder::BE;
507    use bytes::BytesMut;
508    use hashbrown::HashMap;
509
510    #[test]
511    fn test_nested_map() {
512        let mut values = HashMap::new();
513        values.insert(100, HashMap::from([(1, 2), (3, 4)]));
514        values.insert(3, HashMap::new());
515        values.insert(1000, HashMap::from([(7, 8), (9, 4)]));
516
517        let mut buf = BytesMut::new();
518        CompactABI::encode(&values, &mut buf, 0).unwrap();
519
520        let encoded = buf.freeze();
521        let expected_encoded = "03000000140000000c000000200000005c0000000300000064000000e8030000000000003c000000000000003c00000000000000020000003c000000080000004400000008000000020000004c0000000800000054000000080000000100000003000000020000000400000007000000090000000800000004000000";
522
523        assert_eq!(hex::encode(&encoded), expected_encoded, "Encoding mismatch");
524
525        let decoded = CompactABI::<HashMap<i32, HashMap<i32, i32>>>::decode(&encoded, 0).unwrap();
526        assert_eq!(values, decoded);
527
528        let header =
529            CompactABI::<HashMap<i32, HashMap<i32, i32>>>::partial_decode(&encoded, 0).unwrap();
530
531        assert_eq!(header, (20, 104));
532        println!("Header: {:?}", header);
533    }
534
535    #[test]
536    fn test_vector_of_maps() {
537        let values = vec![
538            HashMap::from([(1, 2), (3, 4)]),
539            HashMap::new(),
540            HashMap::from([(7, 8), (9, 4)]),
541        ];
542
543        let mut buf = BytesMut::new();
544        CompactABI::encode(&values, &mut buf, 0).unwrap();
545
546        let result = buf.freeze();
547        println!("{}", hex::encode(&result));
548
549        let expected_encoded = "030000000c0000005c000000020000003c000000080000004400000008000000000000004c000000000000004c00000000000000020000004c0000000800000054000000080000000100000003000000020000000400000007000000090000000800000004000000";
550
551        assert_eq!(hex::encode(&result), expected_encoded, "Encoding mismatch");
552        let bytes = result.clone();
553        let values2 = CompactABI::<Vec<HashMap<u32, u32>>>::decode(&bytes, 0).unwrap();
554        assert_eq!(values, values2);
555    }
556
557    #[test]
558    fn test_map_of_vectors() {
559        let mut values = HashMap::new();
560        values.insert(vec![0, 1, 2], vec![3, 4, 5]);
561        values.insert(vec![3, 1, 2], vec![3, 4, 5]);
562        values.insert(vec![0, 1, 6], vec![3, 4, 5]);
563        let mut buf = BytesMut::new();
564
565        CompactABI::encode(&values, &mut buf, 0).unwrap();
566        let encoded = buf.freeze();
567
568        // Note: The expected encoded string might need to be updated based on the new encoding
569        // format
570        let expected_encoded = "0300000014000000480000005c0000004800000003000000240000000c00000003000000300000000c000000030000003c0000000c00000000000000010000000200000000000000010000000600000003000000010000000200000003000000240000000c00000003000000300000000c000000030000003c0000000c000000030000000400000005000000030000000400000005000000030000000400000005000000";
571        assert_eq!(hex::encode(&encoded), expected_encoded, "Encoding mismatch");
572
573        let values2 = CompactABI::<HashMap<Vec<i32>, Vec<i32>>>::decode(&encoded, 0).unwrap();
574        assert_eq!(values, values2);
575    }
576
577    #[test]
578    fn test_set() {
579        let values = HashSet::from([1, 2, 3]);
580        let mut buf = BytesMut::new();
581
582        CompactABI::encode(&values, &mut buf, 0).unwrap();
583        let encoded = buf.freeze();
584
585        println!("{}", hex::encode(&encoded));
586        let expected_encoded = "030000000c0000000c000000010000000200000003000000";
587        assert_eq!(hex::encode(&encoded), expected_encoded, "Encoding mismatch");
588
589        let values2 = CompactABI::<HashSet<i32>>::decode(&encoded, 0).unwrap();
590        assert_eq!(values, values2);
591    }
592
593    #[test]
594    fn test_set_is_sorted() {
595        let values1 = HashSet::from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
596        let mut buf1 = BytesMut::new();
597
598        CompactABI::encode(&values1, &mut buf1, 0).unwrap();
599
600        let values2 = HashSet::from([8, 3, 2, 4, 5, 9, 7, 1, 6]);
601        let mut buf2 = BytesMut::new();
602
603        CompactABI::encode(&values2, &mut buf2, 0).unwrap();
604
605        assert_eq!(&buf1.chunk(), &buf2.chunk());
606    }
607
608    #[test]
609    fn test_set_solidity() {
610        let values = HashSet::from([1, 2, 3]);
611        let mut buf = BytesMut::new();
612        SolidityABI::encode(&values, &mut buf, 0).unwrap();
613        let encoded = buf.freeze();
614        print_bytes::<BE, 32>(&encoded);
615
616        let values2 = SolidityABI::<HashSet<i32>>::decode(&encoded, 0).unwrap();
617        println!("values2: {:?}", values2);
618        assert_eq!(values, values2, "Decoding mismatch for Solidity");
619    }
620
621    #[test]
622    fn test_set_solidity_is_sorted() {
623        let values1 = HashSet::from([1, 2, 3, 4, 5, 6, 7, 8, 9]);
624        let mut buf1 = BytesMut::new();
625
626        SolidityABI::encode(&values1, &mut buf1, 0).unwrap();
627
628        let values2 = HashSet::from([8, 3, 2, 4, 5, 9, 7, 1, 6]);
629        let mut buf2 = BytesMut::new();
630
631        SolidityABI::encode(&values2, &mut buf2, 0).unwrap();
632
633        assert_eq!(
634            &buf1.chunk(),
635            &buf2.chunk(),
636            "Solidity encoding is not sorted"
637        );
638    }
639}