reth_codecs/
lib.rs

1//! Compact codec.
2//!
3//! *Warning*: The `Compact` encoding format and its implementations are
4//! designed for storing and retrieving data internally. They are not hardened
5//! to safely read potentially malicious data.
6//!
7//! ## Feature Flags
8//!
9//! - `alloy`: [Compact] implementation for various alloy types.
10
11#![doc(
12    html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
13    html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
14    issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
15)]
16#![cfg_attr(not(test), warn(unused_crate_dependencies))]
17#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
18#![cfg_attr(not(feature = "std"), no_std)]
19
20extern crate alloc;
21
22pub use reth_codecs_derive::*;
23use serde as _;
24
25use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U256};
26use bytes::{Buf, BufMut};
27
28use alloc::{
29    borrow::{Cow, ToOwned},
30    vec::Vec,
31};
32
33#[cfg(feature = "test-utils")]
34pub mod alloy;
35
36#[cfg(not(feature = "test-utils"))]
37#[cfg(any(test, feature = "alloy"))]
38mod alloy;
39
40pub mod txtype;
41
42#[cfg(any(test, feature = "test-utils"))]
43pub mod test_utils;
44
45// Used by generated code and doc tests. Not public API.
46#[doc(hidden)]
47#[path = "private.rs"]
48pub mod __private;
49
50/// Trait that implements the `Compact` codec.
51///
52/// When deriving the trait for custom structs, be aware of certain limitations/recommendations:
53/// * Works best with structs that only have native types (eg. u64, B256, U256).
54/// * Fixed array types (B256, Address, Bloom) are not compacted.
55/// * Max size of `T` in `Option<T>` or `Vec<T>` shouldn't exceed `0xffff`.
56/// * Any `Bytes` field **should be placed last**.
57/// * Any other type which is not known to the derive module **should be placed last** in they
58///   contain a `Bytes` field.
59///
60/// The last two points make it easier to decode the data without saving the length on the
61/// `StructFlags`. It will fail compilation if it's not respected. If they're alias to known types,
62/// add their definitions to `get_bit_size()` or `known_types` in `generator.rs`.
63///
64/// Regarding the `specialized_to/from_compact` methods: Mainly used as a workaround for not being
65/// able to specialize an impl over certain types like `Vec<T>`/`Option<T>` where `T` is a fixed
66/// size array like `Vec<B256>`.
67///
68/// ## Caution
69///
70/// Due to the bitfields, every type change on the rust type (e.g. `U256` to `u64`) is a breaking
71/// change and will lead to a new, incompatible [`Compact`] implementation. Implementers must take
72/// special care when changing or rearranging fields.
73pub trait Compact: Sized {
74    /// Takes a buffer which can be written to. *Ideally*, it returns the length written to.
75    fn to_compact<B>(&self, buf: &mut B) -> usize
76    where
77        B: bytes::BufMut + AsMut<[u8]>;
78
79    /// Takes a buffer which can be read from. Returns the object and `buf` with its internal cursor
80    /// advanced (eg.`.advance(len)`).
81    ///
82    /// `len` can either be the `buf` remaining length, or the length of the compacted type.
83    ///
84    /// It will panic, if `len` is smaller than `buf.len()`.
85    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]);
86
87    /// "Optional": If there's no good reason to use it, don't.
88    #[inline]
89    fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
90    where
91        B: bytes::BufMut + AsMut<[u8]>,
92    {
93        self.to_compact(buf)
94    }
95
96    /// "Optional": If there's no good reason to use it, don't.
97    #[inline]
98    fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
99        Self::from_compact(buf, len)
100    }
101}
102
103impl Compact for alloc::string::String {
104    fn to_compact<B>(&self, buf: &mut B) -> usize
105    where
106        B: bytes::BufMut + AsMut<[u8]>,
107    {
108        self.as_bytes().to_compact(buf)
109    }
110
111    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
112        let (vec, buf) = Vec::<u8>::from_compact(buf, len);
113        let string = Self::from_utf8(vec).unwrap(); // Safe conversion
114        (string, buf)
115    }
116}
117
118impl<T: Compact> Compact for &T {
119    fn to_compact<B>(&self, buf: &mut B) -> usize
120    where
121        B: BufMut + AsMut<[u8]>,
122    {
123        (*self).to_compact(buf)
124    }
125
126    fn from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
127        unimplemented!()
128    }
129}
130
131/// To be used with `Option<CompactPlaceholder>` to place or replace one bit on the bitflag struct.
132pub type CompactPlaceholder = ();
133
134impl Compact for CompactPlaceholder {
135    #[inline]
136    fn to_compact<B>(&self, _: &mut B) -> usize
137    where
138        B: bytes::BufMut + AsMut<[u8]>,
139    {
140        0
141    }
142
143    #[inline]
144    fn from_compact(buf: &[u8], _: usize) -> (Self, &[u8]) {
145        ((), buf)
146    }
147}
148
149macro_rules! impl_uint_compact {
150    ($($name:tt),+) => {
151        $(
152            impl Compact for $name {
153                #[inline]
154                fn to_compact<B>(&self, buf: &mut B) -> usize
155                    where B: bytes::BufMut + AsMut<[u8]>
156                {
157                    let leading = self.leading_zeros() as usize / 8;
158                    buf.put_slice(&self.to_be_bytes()[leading..]);
159                    core::mem::size_of::<$name>() - leading
160                }
161
162                #[inline]
163                fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
164                    if len == 0 {
165                        return (0, buf);
166                    }
167
168                    let mut arr = [0; core::mem::size_of::<$name>()];
169                    arr[core::mem::size_of::<$name>() - len..].copy_from_slice(&buf[..len]);
170                    buf.advance(len);
171                    ($name::from_be_bytes(arr), buf)
172                }
173            }
174        )+
175    };
176}
177
178impl_uint_compact!(u8, u64, u128);
179
180impl<T> Compact for Vec<T>
181where
182    T: Compact,
183{
184    /// Returns 0 since we won't include it in the `StructFlags`.
185    #[inline]
186    fn to_compact<B>(&self, buf: &mut B) -> usize
187    where
188        B: bytes::BufMut + AsMut<[u8]>,
189    {
190        self.as_slice().to_compact(buf)
191    }
192
193    #[inline]
194    fn from_compact(buf: &[u8], _: usize) -> (Self, &[u8]) {
195        let (length, mut buf) = decode_varuint(buf);
196        let mut list = Self::with_capacity(length);
197        for _ in 0..length {
198            let len;
199            (len, buf) = decode_varuint(buf);
200
201            let (element, _) = T::from_compact(&buf[..len], len);
202            buf.advance(len);
203
204            list.push(element);
205        }
206
207        (list, buf)
208    }
209
210    /// To be used by fixed sized types like `Vec<B256>`.
211    #[inline]
212    fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
213    where
214        B: bytes::BufMut + AsMut<[u8]>,
215    {
216        self.as_slice().specialized_to_compact(buf)
217    }
218
219    /// To be used by fixed sized types like `Vec<B256>`.
220    #[inline]
221    fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
222        let (length, mut buf) = decode_varuint(buf);
223        let mut list = Self::with_capacity(length);
224
225        for _ in 0..length {
226            let element;
227            (element, buf) = T::from_compact(buf, len);
228            list.push(element);
229        }
230
231        (list, buf)
232    }
233}
234
235impl<T> Compact for &[T]
236where
237    T: Compact,
238{
239    /// Returns 0 since we won't include it in the `StructFlags`.
240    #[inline]
241    fn to_compact<B>(&self, buf: &mut B) -> usize
242    where
243        B: bytes::BufMut + AsMut<[u8]>,
244    {
245        encode_varuint(self.len(), buf);
246
247        let mut tmp: Vec<u8> = Vec::with_capacity(64);
248
249        for element in *self {
250            tmp.clear();
251
252            // We don't know the length until we compact it
253            let length = element.to_compact(&mut tmp);
254            encode_varuint(length, buf);
255
256            buf.put_slice(&tmp);
257        }
258
259        0
260    }
261
262    #[inline]
263    fn from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
264        unimplemented!()
265    }
266
267    /// To be used by fixed sized types like `&[B256]`.
268    #[inline]
269    fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
270    where
271        B: bytes::BufMut + AsMut<[u8]>,
272    {
273        encode_varuint(self.len(), buf);
274        for element in *self {
275            element.to_compact(buf);
276        }
277        0
278    }
279
280    #[inline]
281    fn specialized_from_compact(_: &[u8], _: usize) -> (Self, &[u8]) {
282        unimplemented!()
283    }
284}
285
286impl<T> Compact for Option<T>
287where
288    T: Compact,
289{
290    /// Returns 0 for `None` and 1 for `Some(_)`.
291    #[inline]
292    fn to_compact<B>(&self, buf: &mut B) -> usize
293    where
294        B: bytes::BufMut + AsMut<[u8]>,
295    {
296        let Some(element) = self else { return 0 };
297
298        // We don't know the length of the element until we compact it.
299        let mut tmp = Vec::with_capacity(64);
300        let length = element.to_compact(&mut tmp);
301
302        encode_varuint(length, buf);
303
304        buf.put_slice(&tmp);
305
306        1
307    }
308
309    #[inline]
310    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
311        if len == 0 {
312            return (None, buf)
313        }
314
315        let (len, mut buf) = decode_varuint(buf);
316
317        let (element, _) = T::from_compact(&buf[..len], len);
318        buf.advance(len);
319
320        (Some(element), buf)
321    }
322
323    /// To be used by fixed sized types like `Option<B256>`.
324    #[inline]
325    fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
326    where
327        B: bytes::BufMut + AsMut<[u8]>,
328    {
329        if let Some(element) = self {
330            element.to_compact(buf);
331            1
332        } else {
333            0
334        }
335    }
336
337    /// To be used by fixed sized types like `Option<B256>`.
338    #[inline]
339    fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
340        if len == 0 {
341            return (None, buf)
342        }
343
344        let (element, buf) = T::from_compact(buf, len);
345        (Some(element), buf)
346    }
347}
348
349impl<T: Compact + ToOwned<Owned = T>> Compact for Cow<'_, T> {
350    fn to_compact<B>(&self, buf: &mut B) -> usize
351    where
352        B: bytes::BufMut + AsMut<[u8]>,
353    {
354        self.as_ref().to_compact(buf)
355    }
356
357    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
358        let (element, buf) = T::from_compact(buf, len);
359        (Cow::Owned(element), buf)
360    }
361
362    fn specialized_to_compact<B>(&self, buf: &mut B) -> usize
363    where
364        B: bytes::BufMut + AsMut<[u8]>,
365    {
366        self.as_ref().specialized_to_compact(buf)
367    }
368
369    fn specialized_from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
370        let (element, buf) = T::specialized_from_compact(buf, len);
371        (Cow::Owned(element), buf)
372    }
373}
374
375impl Compact for U256 {
376    #[inline]
377    fn to_compact<B>(&self, buf: &mut B) -> usize
378    where
379        B: bytes::BufMut + AsMut<[u8]>,
380    {
381        let inner = self.to_be_bytes::<32>();
382        let size = 32 - (self.leading_zeros() / 8);
383        buf.put_slice(&inner[32 - size..]);
384        size
385    }
386
387    #[inline]
388    fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
389        if len == 0 {
390            return (Self::ZERO, buf)
391        }
392
393        let mut arr = [0; 32];
394        arr[(32 - len)..].copy_from_slice(&buf[..len]);
395        buf.advance(len);
396        (Self::from_be_bytes(arr), buf)
397    }
398}
399
400impl Compact for Bytes {
401    #[inline]
402    fn to_compact<B>(&self, buf: &mut B) -> usize
403    where
404        B: bytes::BufMut + AsMut<[u8]>,
405    {
406        let len = self.len();
407        buf.put_slice(&self.0);
408        len
409    }
410
411    #[inline]
412    fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
413        (buf.copy_to_bytes(len).into(), buf)
414    }
415}
416
417impl<const N: usize> Compact for [u8; N] {
418    #[inline]
419    fn to_compact<B>(&self, buf: &mut B) -> usize
420    where
421        B: bytes::BufMut + AsMut<[u8]>,
422    {
423        buf.put_slice(&self[..]);
424        N
425    }
426
427    #[inline]
428    fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
429        if len == 0 {
430            return ([0; N], buf)
431        }
432
433        let v = buf[..N].try_into().unwrap();
434        buf.advance(N);
435        (v, buf)
436    }
437}
438
439/// Implements the [`Compact`] trait for wrappers over fixed size byte array types.
440#[macro_export]
441macro_rules! impl_compact_for_wrapped_bytes {
442    ($($name:tt),+) => {
443        $(
444            impl Compact for $name {
445                #[inline]
446                fn to_compact<B>(&self, buf: &mut B) -> usize
447                where
448                    B: bytes::BufMut + AsMut<[u8]>
449                {
450                    self.0.to_compact(buf)
451                }
452
453                #[inline]
454                fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
455                    let (v, buf) = <[u8; core::mem::size_of::<$name>()]>::from_compact(buf, len);
456                    (Self::from(v), buf)
457                }
458            }
459        )+
460    };
461}
462impl_compact_for_wrapped_bytes!(Address, Bloom);
463
464impl<const N: usize> Compact for FixedBytes<N> {
465    #[inline]
466    fn to_compact<B>(&self, buf: &mut B) -> usize
467    where
468        B: bytes::BufMut + AsMut<[u8]>,
469    {
470        self.0.to_compact(buf)
471    }
472
473    #[inline]
474    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
475        let (v, buf) = <[u8; N]>::from_compact(buf, len);
476        (Self::from(v), buf)
477    }
478}
479
480impl Compact for bool {
481    /// `bool` vars go directly to the `StructFlags` and are not written to the buffer.
482    #[inline]
483    fn to_compact<B>(&self, _: &mut B) -> usize
484    where
485        B: bytes::BufMut + AsMut<[u8]>,
486    {
487        *self as usize
488    }
489
490    /// `bool` expects the real value to come in `len`, and does not advance the cursor.
491    #[inline]
492    fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
493        (len != 0, buf)
494    }
495}
496
497fn encode_varuint<B>(mut n: usize, buf: &mut B)
498where
499    B: bytes::BufMut + AsMut<[u8]>,
500{
501    while n >= 0x80 {
502        buf.put_u8((n as u8) | 0x80);
503        n >>= 7;
504    }
505    buf.put_u8(n as u8);
506}
507
508fn decode_varuint(buf: &[u8]) -> (usize, &[u8]) {
509    let mut value = 0;
510
511    for i in 0..33 {
512        let byte = buf[i];
513        value |= usize::from(byte & 0x7F) << (i * 7);
514        if byte < 0x80 {
515            return (value, &buf[i + 1..])
516        }
517    }
518
519    decode_varuint_panic();
520}
521
522#[inline(never)]
523#[cold]
524const fn decode_varuint_panic() -> ! {
525    panic!("could not decode varuint");
526}
527
528#[cfg(test)]
529mod tests {
530    use super::*;
531    use alloy_primitives::B256;
532    use serde::{Deserialize, Serialize};
533
534    #[test]
535    fn compact_bytes() {
536        let arr = [1, 2, 3, 4, 5];
537        let list = Bytes::copy_from_slice(&arr);
538        let mut buf = Vec::with_capacity(list.len() + 1);
539        assert_eq!(list.to_compact(&mut buf), list.len());
540
541        // Add some noise data.
542        buf.push(1);
543
544        assert_eq!(&buf[..arr.len()], &arr);
545        assert_eq!(Bytes::from_compact(&buf, list.len()), (list, vec![1].as_slice()));
546    }
547
548    #[test]
549    fn compact_address() {
550        let mut buf = Vec::with_capacity(21);
551        assert_eq!(Address::ZERO.to_compact(&mut buf), 20);
552        assert_eq!(buf, vec![0; 20]);
553
554        // Add some noise data.
555        buf.push(1);
556
557        // Address shouldn't care about the len passed, since it's not actually compacted.
558        assert_eq!(Address::from_compact(&buf, 1000), (Address::ZERO, vec![1u8].as_slice()));
559    }
560
561    #[test]
562    fn compact_b256() {
563        let mut buf = Vec::with_capacity(32 + 1);
564        assert_eq!(B256::ZERO.to_compact(&mut buf), 32);
565        assert_eq!(buf, vec![0; 32]);
566
567        // Add some noise data.
568        buf.push(1);
569
570        // B256 shouldn't care about the len passed, since it's not actually compacted.
571        assert_eq!(B256::from_compact(&buf, 1000), (B256::ZERO, vec![1u8].as_slice()));
572    }
573
574    #[test]
575    fn compact_bool() {
576        let _vtrue = true;
577        let mut buf = vec![];
578
579        assert_eq!(true.to_compact(&mut buf), 1);
580        // Bool vars go directly to the `StructFlags` and not written to the buf.
581        assert_eq!(buf.len(), 0);
582
583        assert_eq!(false.to_compact(&mut buf), 0);
584        assert_eq!(buf.len(), 0);
585
586        let buf = vec![100u8];
587
588        // Bool expects the real value to come in `len`, and does not advance the cursor.
589        assert_eq!(bool::from_compact(&buf, 1), (true, buf.as_slice()));
590        assert_eq!(bool::from_compact(&buf, 0), (false, buf.as_slice()));
591    }
592
593    #[test]
594    fn compact_option() {
595        let opt = Some(B256::ZERO);
596        let mut buf = Vec::with_capacity(1 + 32);
597
598        assert_eq!(None::<B256>.to_compact(&mut buf), 0);
599        assert_eq!(opt.to_compact(&mut buf), 1);
600        assert_eq!(buf.len(), 1 + 32);
601
602        assert_eq!(Option::<B256>::from_compact(&buf, 1), (opt, vec![].as_slice()));
603
604        // If `None`, it returns the slice at the same cursor position.
605        assert_eq!(Option::<B256>::from_compact(&buf, 0), (None, buf.as_slice()));
606
607        let mut buf = Vec::with_capacity(32);
608        assert_eq!(opt.specialized_to_compact(&mut buf), 1);
609        assert_eq!(buf.len(), 32);
610        assert_eq!(Option::<B256>::specialized_from_compact(&buf, 1), (opt, vec![].as_slice()));
611    }
612
613    #[test]
614    fn compact_vec() {
615        let list = vec![B256::ZERO, B256::ZERO];
616        let mut buf = vec![];
617
618        // Vec doesn't return a total length
619        assert_eq!(list.to_compact(&mut buf), 0);
620
621        // Add some noise data in the end that should be returned by `from_compact`.
622        buf.extend([1u8, 2]);
623
624        let mut remaining_buf = buf.as_slice();
625        remaining_buf.advance(1 + 1 + 32 + 1 + 32);
626
627        assert_eq!(Vec::<B256>::from_compact(&buf, 0), (list, remaining_buf));
628        assert_eq!(remaining_buf, &[1u8, 2]);
629    }
630
631    #[test]
632    fn compact_u256() {
633        let mut buf = vec![];
634
635        assert_eq!(U256::ZERO.to_compact(&mut buf), 0);
636        assert!(buf.is_empty());
637        assert_eq!(U256::from_compact(&buf, 0), (U256::ZERO, vec![].as_slice()));
638
639        assert_eq!(U256::from(2).to_compact(&mut buf), 1);
640        assert_eq!(buf, vec![2u8]);
641        assert_eq!(U256::from_compact(&buf, 1), (U256::from(2), vec![].as_slice()));
642    }
643
644    #[test]
645    fn compact_u64() {
646        let mut buf = vec![];
647
648        assert_eq!(0u64.to_compact(&mut buf), 0);
649        assert!(buf.is_empty());
650        assert_eq!(u64::from_compact(&buf, 0), (0u64, vec![].as_slice()));
651
652        assert_eq!(2u64.to_compact(&mut buf), 1);
653        assert_eq!(buf, vec![2u8]);
654        assert_eq!(u64::from_compact(&buf, 1), (2u64, vec![].as_slice()));
655
656        let mut buf = Vec::with_capacity(8);
657
658        assert_eq!(0xffffffffffffffffu64.to_compact(&mut buf), 8);
659        assert_eq!(&buf, &[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]);
660        assert_eq!(u64::from_compact(&buf, 8), (0xffffffffffffffffu64, vec![].as_slice()));
661    }
662
663    #[test]
664    fn variable_uint() {
665        proptest::proptest!(|(val: usize)| {
666            let mut buf = vec![];
667            encode_varuint(val, &mut buf);
668            let (decoded, read_buf) = decode_varuint(&buf);
669            assert_eq!(val, decoded);
670            assert!(!read_buf.has_remaining());
671        });
672    }
673
674    #[test]
675    fn compact_slice() {
676        let vec_list = vec![B256::ZERO, B256::random(), B256::random(), B256::ZERO];
677
678        // to_compact
679        {
680            let mut vec_buf = vec![];
681            assert_eq!(vec_list.to_compact(&mut vec_buf), 0);
682
683            let mut slice_buf = vec![];
684            assert_eq!(vec_list.as_slice().to_compact(&mut slice_buf), 0);
685
686            assert_eq!(vec_buf, slice_buf);
687        }
688
689        // specialized_to_compact
690        {
691            let mut vec_buf = vec![];
692            assert_eq!(vec_list.specialized_to_compact(&mut vec_buf), 0);
693
694            let mut slice_buf = vec![];
695            assert_eq!(vec_list.as_slice().specialized_to_compact(&mut slice_buf), 0);
696
697            assert_eq!(vec_buf, slice_buf);
698        }
699    }
700
701    #[derive(Debug, PartialEq, Clone, Serialize, Deserialize, Compact, arbitrary::Arbitrary)]
702    #[add_arbitrary_tests(crate, compact)]
703    #[reth_codecs(crate = "crate")]
704    struct TestStruct {
705        f_u64: u64,
706        f_u256: U256,
707        f_bool_t: bool,
708        f_bool_f: bool,
709        f_option_none: Option<B256>,
710        f_option_some: Option<B256>,
711        f_option_some_u64: Option<u64>,
712        f_vec_empty: Vec<Address>,
713        f_vec_some: Vec<Address>,
714    }
715
716    impl Default for TestStruct {
717        fn default() -> Self {
718            Self {
719                f_u64: 1u64,                                    // 4 bits | 1 byte
720                f_u256: U256::from(1u64),                       // 6 bits | 1 byte
721                f_bool_f: false,                                // 1 bit  | 0 bytes
722                f_bool_t: true,                                 // 1 bit  | 0 bytes
723                f_option_none: None,                            // 1 bit  | 0 bytes
724                f_option_some: Some(B256::ZERO),                // 1 bit  | 32 bytes
725                f_option_some_u64: Some(0xffffu64),             // 1 bit  | 1 + 2 bytes
726                f_vec_empty: vec![],                            // 0 bits | 1 bytes
727                f_vec_some: vec![Address::ZERO, Address::ZERO], // 0 bits | 1 + 20*2 bytes
728            }
729        }
730    }
731
732    #[test]
733    fn compact_test_struct() {
734        let test = TestStruct::default();
735        const EXPECTED_SIZE: usize = 2 + // TestStructFlags
736            1 +
737            1 +
738            // 0 + 0 + 0 +
739            32 +
740            1 + 2 +
741            1 +
742            1 + 20 * 2;
743        let mut buf = Vec::with_capacity(EXPECTED_SIZE);
744        assert_eq!(test.to_compact(&mut buf), EXPECTED_SIZE);
745
746        assert_eq!(
747            TestStruct::from_compact(&buf, buf.len()),
748            (TestStruct::default(), vec![].as_slice())
749        );
750    }
751
752    #[derive(
753        Debug, PartialEq, Clone, Default, Serialize, Deserialize, Compact, arbitrary::Arbitrary,
754    )]
755    #[add_arbitrary_tests(crate, compact)]
756    #[reth_codecs(crate = "crate")]
757    enum TestEnum {
758        #[default]
759        Var0,
760        Var1(TestStruct),
761        Var2(u64),
762    }
763
764    #[cfg(test)]
765    #[allow(dead_code)]
766    #[test_fuzz::test_fuzz]
767    fn compact_test_enum_all_variants(var0: TestEnum, var1: TestEnum, var2: TestEnum) {
768        let mut buf = vec![];
769        var0.to_compact(&mut buf);
770        assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var0);
771
772        let mut buf = vec![];
773        var1.to_compact(&mut buf);
774        assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var1);
775
776        let mut buf = vec![];
777        var2.to_compact(&mut buf);
778        assert_eq!(TestEnum::from_compact(&buf, buf.len()).0, var2);
779    }
780
781    #[test]
782    fn compact_test_enum() {
783        let var0 = TestEnum::Var0;
784        let var1 = TestEnum::Var1(TestStruct::default());
785        let var2 = TestEnum::Var2(1u64);
786
787        compact_test_enum_all_variants(var0, var1, var2);
788    }
789}