Skip to main content

fluentbase_codec/
primitive.rs

1use crate::{
2    alloc::string::ToString,
3    encoder::{align_up, get_aligned_indices, get_aligned_slice, is_big_endian, Encoder},
4    error::{CodecError, DecodingError},
5};
6use byteorder::ByteOrder;
7use bytes::{Buf, BytesMut};
8use core::{marker::PhantomData, mem::size_of};
9
10impl<B: ByteOrder, const ALIGN: usize, const SOL_MODE: bool, const IS_STATIC: bool>
11    Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for PhantomData<B>
12{
13    const HEADER_SIZE: usize = 0;
14    const IS_DYNAMIC: bool = false;
15
16    fn encode(&self, _buf: &mut BytesMut, _offset: usize) -> Result<(), CodecError> {
17        Ok(())
18    }
19
20    fn decode(_buf: &impl Buf, _offset: usize) -> Result<Self, CodecError> {
21        Ok(PhantomData)
22    }
23
24    fn partial_decode(_buf: &impl Buf, _offset: usize) -> Result<(usize, usize), CodecError> {
25        Ok((0, 0))
26    }
27}
28
29impl<B: ByteOrder, const ALIGN: usize, const SOL_MODE: bool, const IS_STATIC: bool>
30    Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for u8
31{
32    const HEADER_SIZE: usize = size_of::<u8>();
33    const IS_DYNAMIC: bool = false;
34
35    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
36        let word_size =
37            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE);
38
39        if buf.len() < offset + word_size {
40            buf.resize(offset + word_size, 0);
41        }
42
43        let write_to = get_aligned_slice::<B, ALIGN>(buf, offset, 1);
44
45        write_to[0] = *self;
46
47        Ok(())
48    }
49
50    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
51        let word_size =
52            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE);
53
54        if buf.remaining() < offset + word_size {
55            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
56                expected: offset + word_size,
57                found: buf.remaining(),
58                msg: "buf too small to read aligned u8".to_string(),
59            }));
60        }
61
62        let chunk = &buf.chunk()[offset..];
63        let value = if is_big_endian::<B>() {
64            chunk[word_size - 1]
65        } else {
66            chunk[0]
67        };
68
69        Ok(value)
70    }
71
72    fn partial_decode(_buf: &impl Buf, _offset: usize) -> Result<(usize, usize), CodecError> {
73        Ok((
74            0,
75            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE),
76        ))
77    }
78}
79
80impl<B: ByteOrder, const ALIGN: usize, const SOL_MODE: bool, const IS_STATIC: bool>
81    Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for bool
82{
83    const HEADER_SIZE: usize = core::mem::size_of::<bool>();
84    const IS_DYNAMIC: bool = false;
85
86    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
87        let value: u8 = if *self { 1 } else { 0 };
88
89        <u8 as Encoder<B, ALIGN, SOL_MODE, true>>::encode(&value, buf, offset)
90    }
91
92    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
93        let value = <u8 as Encoder<B, ALIGN, SOL_MODE, true>>::decode(buf, offset)?;
94
95        Ok(value != 0)
96    }
97
98    fn partial_decode(_buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
99        Ok((
100            offset,
101            <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE,
102        ))
103    }
104}
105
106macro_rules! impl_int {
107    ($typ:ty, $read_method:ident, $write_method:ident) => {
108        impl<B: ByteOrder, const ALIGN: usize, const SOL_MODE: bool, const IS_STATIC: bool>
109            Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for $typ
110        {
111            const HEADER_SIZE: usize = core::mem::size_of::<$typ>();
112            const IS_DYNAMIC: bool = false;
113
114            fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
115                let word_size = align_up::<ALIGN>(
116                    <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE,
117                );
118
119                if buf.len() < offset + word_size {
120                    buf.resize(offset + word_size, 0);
121                }
122
123                let (start, end) = get_aligned_indices::<B, ALIGN>(
124                    offset,
125                    <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE,
126                );
127
128                B::$write_method(&mut buf[start..end], *self);
129
130                // Fill the rest of the buffer with 0x00 or 0xFF depending on the sign of the
131                // integer
132                let fill_val = if *self > 0 { 0x00 } else { 0xFF };
133
134                for i in offset..start {
135                    buf[i] = fill_val;
136                }
137
138                B::$write_method(&mut buf[start..end], *self);
139
140                for i in end..(offset + word_size) {
141                    buf[i] = fill_val;
142                }
143
144                Ok(())
145            }
146
147            fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
148                let word_size = align_up::<ALIGN>(
149                    <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE,
150                );
151
152                if buf.remaining() < offset + ALIGN {
153                    return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
154                        expected: offset + ALIGN,
155                        found: buf.remaining(),
156                        msg: "buf too small to decode value".to_string(),
157                    }));
158                }
159
160                let chunk = &buf.chunk()[offset..];
161                let value = if is_big_endian::<B>() {
162                    B::$read_method(
163                        &chunk[word_size
164                            - <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE
165                            ..word_size],
166                    )
167                } else {
168                    B::$read_method(
169                        &chunk[..<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE],
170                    )
171                };
172
173                Ok(value)
174            }
175
176            fn partial_decode(
177                _buf: &impl Buf,
178                offset: usize,
179            ) -> Result<(usize, usize), CodecError> {
180                Ok((
181                    offset,
182                    <Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE,
183                ))
184            }
185        }
186    };
187}
188
189impl_int!(u16, read_u16, write_u16);
190impl_int!(u32, read_u32, write_u32);
191impl_int!(u64, read_u64, write_u64);
192impl_int!(i16, read_i16, write_i16);
193impl_int!(i32, read_i32, write_i32);
194impl_int!(i64, read_i64, write_i64);
195
196/// Encodes and decodes `Option<T>` where `T` is an encoder.
197/// The encoded data is prefixed with a single byte that indicates whether the Option is Some or
198/// None. Single byte will be aligned to ALIGN.
199impl<T, B: ByteOrder, const ALIGN: usize, const SOL_MODE: bool, const IS_STATIC: bool>
200    Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for Option<T>
201where
202    T: Sized + Encoder<B, ALIGN, SOL_MODE, true> + Default,
203{
204    const HEADER_SIZE: usize = 1 + T::HEADER_SIZE;
205    const IS_DYNAMIC: bool = false;
206
207    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
208        let aligned_header =
209            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE);
210        if buf.len() < offset + aligned_header {
211            buf.resize(offset + aligned_header, 0);
212        }
213        // Get aligned slice for the option flag
214        let flag_slice = get_aligned_slice::<B, ALIGN>(buf, offset, 1);
215        flag_slice[0] = if self.is_some() { 1 } else { 0 };
216
217        let inner_offset = offset + ALIGN;
218
219        match self {
220            Some(inner_value) => inner_value.encode(buf, inner_offset)?,
221            None => {
222                let default_value = T::default();
223                default_value.encode(buf, inner_offset)?;
224            }
225        };
226
227        Ok(())
228    }
229
230    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
231        let aligned_header =
232            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE);
233
234        if buf.remaining() < offset + aligned_header {
235            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
236                expected: offset + aligned_header,
237                found: buf.remaining(),
238                msg: "buf too small".to_string(),
239            }));
240        }
241
242        let chunk = &buf.chunk()[offset..];
243        let option_flag = if is_big_endian::<B>() {
244            chunk[aligned_header - 1]
245        } else {
246            chunk[0]
247        };
248
249        let chunk = &buf.chunk()[offset + ALIGN..];
250
251        if option_flag != 0 {
252            let inner_value = T::decode(&chunk, 0)?;
253            Ok(Some(inner_value))
254        } else {
255            Ok(None)
256        }
257    }
258
259    fn partial_decode(buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
260        let aligned_header =
261            align_up::<ALIGN>(<Self as Encoder<B, ALIGN, SOL_MODE, IS_STATIC>>::HEADER_SIZE);
262
263        if buf.remaining() < offset + aligned_header {
264            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
265                expected: offset + aligned_header,
266                found: buf.remaining(),
267                msg: "buf too small".to_string(),
268            }));
269        }
270
271        let chunk = &buf.chunk()[offset..];
272        let option_flag = if is_big_endian::<B>() {
273            chunk[ALIGN - 1]
274        } else {
275            chunk[0]
276        };
277
278        let chunk = &buf.chunk()[offset + ALIGN..];
279
280        if option_flag != 0 {
281            let (_, inner_size) = T::partial_decode(&chunk, 0)?;
282            Ok((offset, aligned_header + inner_size))
283        } else {
284            let aligned_data_size = align_up::<ALIGN>(T::HEADER_SIZE);
285            Ok((offset, aligned_header + aligned_data_size))
286        }
287    }
288}
289
290impl<
291        T,
292        B: ByteOrder,
293        const ALIGN: usize,
294        const SOL_MODE: bool,
295        const N: usize,
296        const IS_STATIC: bool,
297    > Encoder<B, ALIGN, SOL_MODE, IS_STATIC> for [T; N]
298where
299    T: Sized + Encoder<B, ALIGN, SOL_MODE, IS_STATIC> + Default + Copy,
300{
301    const HEADER_SIZE: usize = align_up::<ALIGN>(T::HEADER_SIZE) * N;
302    const IS_DYNAMIC: bool = false;
303
304    fn encode(&self, buf: &mut BytesMut, offset: usize) -> Result<(), CodecError> {
305        let item_size = align_up::<ALIGN>(T::HEADER_SIZE);
306
307        if buf.len() < offset + (item_size * N) {
308            buf.resize(offset + (item_size * N), 0);
309        }
310
311        for (i, item) in self.iter().enumerate() {
312            item.encode(buf, offset + (item_size * i))?;
313        }
314
315        Ok(())
316    }
317
318    fn decode(buf: &impl Buf, offset: usize) -> Result<Self, CodecError> {
319        let item_size = align_up::<ALIGN>(T::HEADER_SIZE);
320        let total_size = offset + (item_size * N);
321
322        if buf.remaining() < total_size {
323            return Err(CodecError::Decoding(DecodingError::BufferTooSmall {
324                expected: total_size,
325                found: buf.remaining(),
326                msg: "buf too small to decode [T; N]".to_string(),
327            }));
328        }
329
330        let mut result = [T::default(); N];
331
332        for (i, item) in result.iter_mut().enumerate() {
333            *item = T::decode(buf, offset + (item_size * i))?;
334        }
335
336        Ok(result)
337    }
338
339    fn partial_decode(_buf: &impl Buf, offset: usize) -> Result<(usize, usize), CodecError> {
340        let item_size = align_up::<ALIGN>(T::HEADER_SIZE);
341        let total_size = item_size * N;
342
343        Ok((offset, total_size))
344    }
345}
346
347#[cfg(test)]
348mod tests {
349    use super::*;
350    use crate::SolidityPackedABI;
351    use byteorder::{BigEndian, LittleEndian};
352    use bytes::{Bytes, BytesMut};
353
354    #[test]
355    fn test_u8_be_encode_decode() {
356        let original: u8 = 1;
357        const ALIGNMENT: usize = 32;
358
359        let mut buf = BytesMut::zeroed(ALIGNMENT);
360
361        println!("Buffer capacity: {}", buf.capacity());
362
363        let encoding_result =
364            <u8 as Encoder<BigEndian, { ALIGNMENT }, false, true>>::encode(&original, &mut buf, 0);
365
366        assert!(encoding_result.is_ok());
367
368        let expected_encoded = "0000000000000000000000000000000000000000000000000000000000000001";
369
370        assert_eq!(hex::encode(&buf), expected_encoded);
371
372        let buf_for_decode = buf.clone().freeze();
373        let decoded =
374            <u8 as Encoder<BigEndian, { ALIGNMENT }, false, true>>::decode(&buf_for_decode, 0)
375                .unwrap();
376
377        assert_eq!(original, decoded);
378        println!("encoded: {:?}", buf);
379
380        let partial_decoded =
381            <u8 as Encoder<BigEndian, { ALIGNMENT }, false, true>>::partial_decode(
382                &buf.clone().freeze(),
383                0,
384            )
385            .unwrap();
386        assert_eq!(partial_decoded, (0, ALIGNMENT));
387    }
388
389    #[test]
390    fn test_u8_le_encode_decode() {
391        let original: u8 = 1;
392        const ALIGNMENT: usize = 32;
393        let mut buf = BytesMut::zeroed(ALIGNMENT);
394
395        println!("Buffer capacity: {}", buf.capacity());
396
397        let encoding_result = <u8 as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::encode(
398            &original, &mut buf, 0,
399        );
400
401        assert!(encoding_result.is_ok());
402
403        let expected_encoded = "0100000000000000000000000000000000000000000000000000000000000000";
404
405        let encoded = buf.freeze();
406        println!("Encoded: {:?}", encoded);
407        assert_eq!(hex::encode(&encoded), expected_encoded);
408
409        let decoded =
410            <u8 as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::decode(&encoded, 0).unwrap();
411        println!("Decoded: {}", decoded);
412
413        assert_eq!(original, decoded);
414
415        let partial_decoded =
416            <u8 as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::partial_decode(&encoded, 0)
417                .unwrap();
418
419        assert_eq!(partial_decoded, (0, 32));
420    }
421
422    #[test]
423    fn test_bool_be_encode_decode() {
424        let original: bool = true;
425        const ALIGNMENT: usize = 32;
426
427        let mut buf = BytesMut::zeroed(ALIGNMENT);
428
429        println!("Buffer capacity: {}", buf.capacity());
430
431        let encoding_result = <bool as Encoder<BigEndian, { ALIGNMENT }, false, true>>::encode(
432            &original, &mut buf, 0,
433        );
434
435        assert!(encoding_result.is_ok());
436
437        let expected_encoded = "0000000000000000000000000000000000000000000000000000000000000001";
438
439        assert_eq!(hex::encode(&buf), expected_encoded);
440
441        let buf_for_decode = buf.clone().freeze();
442        let decoded =
443            <bool as Encoder<BigEndian, { ALIGNMENT }, false, true>>::decode(&buf_for_decode, 0)
444                .unwrap();
445
446        assert_eq!(original, decoded);
447        println!("encoded: {:?}", buf);
448
449        let partial_decoded =
450            <bool as Encoder<BigEndian, { ALIGNMENT }, false, true>>::partial_decode(
451                &buf.clone().freeze(),
452                0,
453            )
454            .unwrap();
455        assert_eq!(partial_decoded, (0, 1));
456    }
457
458    #[test]
459    fn test_bool_le_encode_decode() {
460        let original: bool = true;
461        const ALIGNMENT: usize = 32;
462
463        let mut buf = BytesMut::zeroed(ALIGNMENT);
464
465        println!("Buffer capacity: {}", buf.capacity());
466
467        let encoding_result = <bool as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::encode(
468            &original, &mut buf, 0,
469        );
470
471        assert!(encoding_result.is_ok());
472
473        let expected_encoded = "0100000000000000000000000000000000000000000000000000000000000000";
474
475        assert_eq!(hex::encode(&buf), expected_encoded);
476
477        let buf_for_decode = buf.clone().freeze();
478        let decoded =
479            <bool as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::decode(&buf_for_decode, 0)
480                .unwrap();
481
482        assert_eq!(original, decoded);
483        println!("encoded: {:?}", buf);
484
485        let partial_decoded =
486            <bool as Encoder<LittleEndian, { ALIGNMENT }, false, true>>::partial_decode(
487                &buf.clone().freeze(),
488                0,
489            )
490            .unwrap();
491        assert_eq!(partial_decoded, (0, 1));
492    }
493
494    #[test]
495    fn test_u32_encode_decode_le() {
496        let original: u32 = 0x12345678;
497        let mut buf = BytesMut::new();
498
499        <u32 as Encoder<LittleEndian, 8, false, true>>::encode(&original, &mut buf, 0).unwrap();
500
501        println!("Encoded: {:?}", buf);
502
503        assert_eq!(buf.to_vec(), vec![0x78, 0x56, 0x34, 0x12, 0, 0, 0, 0]);
504
505        let buf_for_decode = buf.freeze();
506        let decoded =
507            <u32 as Encoder<LittleEndian, 8, false, true>>::decode(&buf_for_decode, 0).unwrap();
508
509        assert_eq!(original, decoded);
510    }
511
512    #[test]
513    fn test_u32_encode_decode_be() {
514        let original: u32 = 0x12345678;
515        let mut buf = BytesMut::new();
516
517        <u32 as Encoder<BigEndian, 8, false, true>>::encode(&original, &mut buf, 0).unwrap();
518
519        let encoded = buf.freeze();
520        println!("{:?}", hex::encode(&encoded));
521        assert_eq!(
522            &encoded,
523            &vec![0x00, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78]
524        );
525
526        let decoded = <u32 as Encoder<BigEndian, 8, false, true>>::decode(&encoded, 0).unwrap();
527        println!("Decoded: {}", decoded);
528
529        assert_eq!(original, decoded);
530    }
531
532    #[test]
533    fn test_i64_encode_decode_be() {
534        let original: i64 = 0x1234567890ABCDEF;
535        let mut buf = BytesMut::new();
536
537        <i64 as Encoder<BigEndian, 8, false, true>>::encode(&original, &mut buf, 0).unwrap();
538
539        let encoded = buf.freeze();
540        println!("Encoded: {:?}", hex::encode(&encoded));
541        assert_eq!(
542            &encoded,
543            &vec![0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF]
544        );
545
546        let decoded = <i64 as Encoder<BigEndian, 8, false, true>>::decode(&encoded, 0).unwrap();
547        println!("Decoded: {}", decoded);
548
549        assert_eq!(original, decoded);
550    }
551    #[test]
552    fn test_u32_wasm_abi_encode_decode() {
553        let original: u32 = 0x12345678;
554        let mut buf = BytesMut::new();
555
556        // Encode
557        <u32 as Encoder<LittleEndian, 4, false, true>>::encode(&original, &mut buf, 0).unwrap();
558
559        // Check encoded format
560        assert_eq!(buf.to_vec(), vec![0x78, 0x56, 0x34, 0x12]);
561
562        // Decode
563        let decoded = <u32 as Encoder<LittleEndian, 4, false, true>>::decode(&buf, 0).unwrap();
564
565        // Check decoded value
566        assert_eq!(original, decoded);
567    }
568
569    #[test]
570    fn test_u32_solidity_abi_encode_decode() {
571        let original: u32 = 0x12345678;
572        let mut buf = BytesMut::new();
573
574        // Encode
575        <u32 as Encoder<BigEndian, 32, true, true>>::encode(&original, &mut buf, 0).unwrap();
576
577        // Check encoded format (32 bytes, right-aligned)
578        let expected = vec![
579            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
580            0x12, 0x34, 0x56, 0x78,
581        ];
582        assert_eq!(buf.to_vec(), expected);
583
584        // Decode
585        let decoded = <u32 as Encoder<BigEndian, 32, true, true>>::decode(&buf, 0).unwrap();
586
587        // Check decoded value
588        assert_eq!(original, decoded);
589    }
590
591    #[test]
592    fn test_option_u32_encode_decode() {
593        let original: Option<u32> = Some(0x12345678);
594        let mut buf = BytesMut::with_capacity(8);
595
596        let ok =
597            <Option<u32> as Encoder<LittleEndian, 4, false, true>>::encode(&original, &mut buf, 0);
598        assert!(ok.is_ok());
599
600        let encoded = buf.freeze();
601        println!("Encoded: {:?}", &encoded.to_vec());
602        assert_eq!(
603            encoded,
604            Bytes::from_static(&[0x01, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12])
605        );
606
607        let decoded = <Option<u32> as Encoder<LittleEndian, 4, false, true>>::decode(&encoded, 0);
608
609        assert_eq!(original, decoded.unwrap());
610    }
611
612    #[test]
613    fn test_u8_array_encode_decode_le_with_alignment() {
614        let original: [u8; 5] = [1, 2, 3, 4, 5];
615        let mut buf = BytesMut::new();
616
617        <[u8; 5] as Encoder<LittleEndian, 4, false, true>>::encode(&original, &mut buf, 0).unwrap();
618
619        let encoded = buf.freeze();
620        println!("Encoded: {:?}", hex::encode(&encoded));
621
622        // Check that the encoded data is correct and properly aligned
623        assert_eq!(
624            &encoded.to_vec(),
625            &[
626                0x01, 0x00, 0x00, 0x00, // First byte aligned to 4 bytes
627                0x02, 0x00, 0x00, 0x00, // Second byte aligned to 4 bytes
628                0x03, 0x00, 0x00, 0x00, // Third byte aligned to 4 bytes
629                0x04, 0x00, 0x00, 0x00, // Fourth byte aligned to 4 bytes
630                0x05, 0x00, 0x00, 0x00 // Fifth byte aligned to 4 bytes
631            ]
632        );
633
634        println!("Encoded: {:?}", encoded.to_vec());
635        println!("encoded len: {}", encoded.len());
636        let decoded =
637            <[u8; 5] as Encoder<LittleEndian, 4, false, true>>::decode(&encoded, 0).unwrap();
638        println!("Decoded: {:?}", decoded);
639
640        assert_eq!(original, decoded);
641    }
642
643    #[test]
644    fn test_packed_encoding() {
645        let value1: u32 = 0x12345678;
646        let value2: u16 = 0x9ABC;
647        let value3: u8 = 0xDE;
648        let mut buf = BytesMut::new();
649
650        SolidityPackedABI::<u32>::encode(&value1, &mut buf, 0).unwrap();
651        SolidityPackedABI::<u16>::encode(&value2, &mut buf, 4).unwrap();
652        SolidityPackedABI::<u8>::encode(&value3, &mut buf, 6).unwrap();
653
654        assert_eq!(buf.to_vec(), vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE]);
655    }
656
657    #[test]
658    fn test_packed_array() {
659        let arr: [u16; 3] = [0x1234, 0x5678, 0x9ABC];
660        let mut buf = BytesMut::new();
661
662        // Using the existing implementation with packed parameters
663        SolidityPackedABI::<[u16; 3]>::encode(&arr, &mut buf, 0).unwrap();
664
665        assert_eq!(buf.to_vec(), vec![0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC]);
666
667        let decoded = SolidityPackedABI::<[u16; 3]>::decode(&buf, 0).unwrap();
668        assert_eq!(arr, decoded);
669    }
670}