Skip to main content

alloy_rlp/
encode.rs

1use crate::{Header, EMPTY_STRING_CODE};
2use bytes::{BufMut, Bytes, BytesMut};
3use core::{
4    borrow::Borrow,
5    marker::{PhantomData, PhantomPinned},
6    num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize},
7};
8
9#[allow(unused_imports)]
10use alloc::vec::Vec;
11
12#[cfg(feature = "arrayvec")]
13use arrayvec::ArrayVec;
14
15/// A type that can be encoded via RLP.
16pub trait Encodable {
17    /// Encodes the type into the `out` buffer.
18    fn encode(&self, out: &mut dyn BufMut);
19
20    /// Returns the length of the encoding of this type in bytes.
21    ///
22    /// The default implementation computes this by encoding the type.
23    /// When possible, we recommender implementers override this with a
24    /// specialized implementation.
25    #[inline]
26    fn length(&self) -> usize {
27        let mut out = Vec::new();
28        self.encode(&mut out);
29        out.len()
30    }
31}
32
33// The existence of this function makes the compiler catch if the Encodable
34// trait is "object-safe" or not.
35fn _assert_trait_object(_b: &dyn Encodable) {}
36
37/// Defines the max length of an [`Encodable`] type as a const generic.
38///
39/// # Safety
40///
41/// An invalid value can cause the encoder to panic.
42pub unsafe trait MaxEncodedLen<const LEN: usize>: Encodable {}
43
44/// Defines the max length of an [`Encodable`] type as an associated constant.
45///
46/// # Safety
47///
48/// An invalid value can cause the encoder to panic.
49pub unsafe trait MaxEncodedLenAssoc: Encodable {
50    /// The maximum length.
51    const LEN: usize;
52}
53
54/// Implement [`MaxEncodedLen`] and [`MaxEncodedLenAssoc`] for a type.
55///
56/// # Safety
57///
58/// An invalid value can cause the encoder to panic.
59#[macro_export]
60macro_rules! impl_max_encoded_len {
61    ($t:ty, $len:expr) => {
62        unsafe impl $crate::MaxEncodedLen<{ $len }> for $t {}
63        unsafe impl $crate::MaxEncodedLenAssoc for $t {
64            const LEN: usize = $len;
65        }
66    };
67}
68
69macro_rules! to_be_bytes_trimmed {
70    ($be:ident, $x:expr) => {{
71        $be = $x.to_be_bytes();
72        &$be[($x.leading_zeros() / 8) as usize..]
73    }};
74}
75pub(crate) use to_be_bytes_trimmed;
76
77impl Encodable for [u8] {
78    #[inline]
79    fn length(&self) -> usize {
80        let mut len = self.len();
81        if len != 1 || self[0] >= EMPTY_STRING_CODE {
82            len += length_of_length(len);
83        }
84        len
85    }
86
87    #[inline]
88    fn encode(&self, out: &mut dyn BufMut) {
89        if self.len() != 1 || self[0] >= EMPTY_STRING_CODE {
90            Header { list: false, payload_length: self.len() }.encode(out);
91        }
92        out.put_slice(self);
93    }
94}
95
96impl<T: ?Sized> Encodable for PhantomData<T> {
97    #[inline]
98    fn length(&self) -> usize {
99        0
100    }
101
102    #[inline]
103    fn encode(&self, _out: &mut dyn BufMut) {}
104}
105
106impl Encodable for PhantomPinned {
107    #[inline]
108    fn length(&self) -> usize {
109        0
110    }
111
112    #[inline]
113    fn encode(&self, _out: &mut dyn BufMut) {}
114}
115
116impl<const N: usize> Encodable for [u8; N] {
117    #[inline]
118    fn length(&self) -> usize {
119        self[..].length()
120    }
121
122    #[inline]
123    fn encode(&self, out: &mut dyn BufMut) {
124        self[..].encode(out);
125    }
126}
127
128unsafe impl<const N: usize> MaxEncodedLenAssoc for [u8; N] {
129    const LEN: usize = N + length_of_length(N);
130}
131
132impl Encodable for str {
133    #[inline]
134    fn length(&self) -> usize {
135        self.as_bytes().length()
136    }
137
138    #[inline]
139    fn encode(&self, out: &mut dyn BufMut) {
140        self.as_bytes().encode(out)
141    }
142}
143
144impl Encodable for bool {
145    #[inline]
146    fn length(&self) -> usize {
147        // a `bool` is always `< EMPTY_STRING_CODE`
148        1
149    }
150
151    #[inline]
152    fn encode(&self, out: &mut dyn BufMut) {
153        // inlined `(*self as u8).encode(out)`
154        out.put_u8(if *self { 1 } else { EMPTY_STRING_CODE });
155    }
156}
157
158impl_max_encoded_len!(bool, <u8 as MaxEncodedLenAssoc>::LEN);
159
160macro_rules! uint_impl {
161    ($($t:ty),+ $(,)?) => {$(
162        impl Encodable for $t {
163            #[inline]
164            fn length(&self) -> usize {
165                let x = *self;
166                if x < EMPTY_STRING_CODE as $t {
167                    1
168                } else {
169                    1 + (<$t>::BITS as usize / 8) - (x.leading_zeros() as usize / 8)
170                }
171            }
172
173            #[inline]
174            fn encode(&self, out: &mut dyn BufMut) {
175                let x = *self;
176                if x == 0 {
177                    out.put_u8(EMPTY_STRING_CODE);
178                } else if x < EMPTY_STRING_CODE as $t {
179                    out.put_u8(x as u8);
180                } else {
181                    let be;
182                    let be = to_be_bytes_trimmed!(be, x);
183                    out.put_u8(EMPTY_STRING_CODE + be.len() as u8);
184                    out.put_slice(be);
185                }
186            }
187        }
188
189        impl_max_encoded_len!($t, {
190            let bytes = <$t>::BITS as usize / 8;
191            bytes + length_of_length(bytes)
192        });
193    )+};
194}
195
196uint_impl!(u8, u16, u32, u64, usize, u128);
197
198macro_rules! nonzero_uint_impl {
199    ($($t:ty => $inner:ty),+ $(,)?) => {$(
200        impl Encodable for $t {
201            #[inline]
202            fn length(&self) -> usize {
203                self.get().length()
204            }
205
206            #[inline]
207            fn encode(&self, out: &mut dyn BufMut) {
208                self.get().encode(out);
209            }
210        }
211
212        impl_max_encoded_len!($t, <$inner as MaxEncodedLenAssoc>::LEN);
213    )+};
214}
215
216nonzero_uint_impl! {
217    NonZeroU8 => u8,
218    NonZeroU16 => u16,
219    NonZeroU32 => u32,
220    NonZeroU64 => u64,
221    NonZeroUsize => usize,
222    NonZeroU128 => u128,
223}
224
225impl<T: Encodable> Encodable for Vec<T> {
226    #[inline]
227    fn length(&self) -> usize {
228        list_length(self)
229    }
230
231    #[inline]
232    fn encode(&self, out: &mut dyn BufMut) {
233        encode_list(self, out)
234    }
235}
236
237macro_rules! deref_impl {
238    ($($(#[$attr:meta])* [$($gen:tt)*] $t:ty),+ $(,)?) => {$(
239        $(#[$attr])*
240        impl<$($gen)*> Encodable for $t {
241            #[inline]
242            fn length(&self) -> usize {
243                (**self).length()
244            }
245
246            #[inline]
247            fn encode(&self, out: &mut dyn BufMut) {
248                (**self).encode(out)
249            }
250        }
251    )+};
252}
253
254deref_impl! {
255    [] alloc::string::String,
256    [] Bytes,
257    [] BytesMut,
258    #[cfg(feature = "arrayvec")]
259    [const N: usize] ArrayVec<u8, N>,
260    [T: ?Sized + Encodable] &T,
261    [T: ?Sized + Encodable] &mut T,
262    [T: ?Sized + Encodable] alloc::boxed::Box<T>,
263    [T: ?Sized + alloc::borrow::ToOwned + Encodable] alloc::borrow::Cow<'_, T>,
264    [T: ?Sized + Encodable] alloc::rc::Rc<T>,
265    #[cfg(target_has_atomic = "ptr")]
266    [T: ?Sized + Encodable] alloc::sync::Arc<T>,
267}
268
269#[cfg(any(feature = "std", feature = "core-net"))]
270mod std_support {
271    use super::*;
272    #[cfg(all(feature = "core-net", not(feature = "std")))]
273    use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
274    #[cfg(feature = "std")]
275    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
276
277    impl Encodable for IpAddr {
278        #[inline]
279        fn length(&self) -> usize {
280            match self {
281                Self::V4(ip) => ip.length(),
282                Self::V6(ip) => ip.length(),
283            }
284        }
285
286        #[inline]
287        fn encode(&self, out: &mut dyn BufMut) {
288            match self {
289                Self::V4(ip) => ip.encode(out),
290                Self::V6(ip) => ip.encode(out),
291            }
292        }
293    }
294
295    impl Encodable for Ipv4Addr {
296        #[inline]
297        fn length(&self) -> usize {
298            self.octets().length()
299        }
300
301        #[inline]
302        fn encode(&self, out: &mut dyn BufMut) {
303            self.octets().encode(out)
304        }
305    }
306
307    impl Encodable for Ipv6Addr {
308        #[inline]
309        fn length(&self) -> usize {
310            self.octets().length()
311        }
312
313        #[inline]
314        fn encode(&self, out: &mut dyn BufMut) {
315            self.octets().encode(out)
316        }
317    }
318}
319
320/// Encode a value.
321///
322/// Prefer using [`encode_fixed_size`] if a type implements [`MaxEncodedLen`].
323#[inline]
324pub fn encode<T: Encodable>(value: T) -> Vec<u8> {
325    let mut out = Vec::with_capacity(value.length());
326    value.encode(&mut out);
327    out
328}
329
330/// Encode a type with a known maximum size.
331#[cfg(feature = "arrayvec")]
332#[inline]
333pub fn encode_fixed_size<T: MaxEncodedLen<LEN>, const LEN: usize>(value: &T) -> ArrayVec<u8, LEN> {
334    let mut vec = ArrayVec::<u8, LEN>::new();
335
336    // SAFETY: We're casting uninitalized memory to a slice of bytes to be written into.
337    let mut out = unsafe { core::slice::from_raw_parts_mut(vec.as_mut_ptr(), LEN) };
338    value.encode(&mut out);
339    let written = LEN - out.len();
340
341    // SAFETY: `written <= LEN` and all bytes are initialized.
342    unsafe { vec.set_len(written) };
343    vec
344}
345
346/// Calculate the length of a list.
347#[inline]
348pub fn list_length<B, T>(list: &[B]) -> usize
349where
350    B: Borrow<T>,
351    T: ?Sized + Encodable,
352{
353    let payload_length = rlp_list_header(list).payload_length;
354    payload_length + length_of_length(payload_length)
355}
356
357/// Encode a list of items.
358#[inline]
359pub fn encode_list<B, T>(values: &[B], out: &mut dyn BufMut)
360where
361    B: Borrow<T>,
362    T: ?Sized + Encodable,
363{
364    rlp_list_header(values).encode(out);
365    for value in values {
366        value.borrow().encode(out);
367    }
368}
369
370/// Encode all items from an iterator.
371///
372/// This clones the iterator. Prefer [`encode_list`] if possible.
373#[inline]
374pub fn encode_iter<I, B, T>(values: I, out: &mut dyn BufMut)
375where
376    I: Iterator<Item = B> + Clone,
377    B: Borrow<T>,
378    T: ?Sized + Encodable,
379{
380    let mut h = Header { list: true, payload_length: 0 };
381    for t in values.clone() {
382        h.payload_length += t.borrow().length();
383    }
384
385    h.encode(out);
386    for value in values {
387        value.borrow().encode(out);
388    }
389}
390
391/// Determine the length in bytes of the length prefix of an RLP item.
392#[inline]
393pub const fn length_of_length(payload_length: usize) -> usize {
394    if payload_length < 56 {
395        1
396    } else {
397        1 + (usize::BITS as usize / 8) - payload_length.leading_zeros() as usize / 8
398    }
399}
400
401#[inline]
402fn rlp_list_header<B, T>(values: &[B]) -> Header
403where
404    B: Borrow<T>,
405    T: ?Sized + Encodable,
406{
407    let mut h = Header { list: true, payload_length: 0 };
408    for value in values {
409        h.payload_length += value.borrow().length();
410    }
411    h
412}
413
414#[cfg(test)]
415mod tests {
416    use super::*;
417    use core::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
418    use hex_literal::hex;
419
420    fn encoded_list<T: Encodable + Clone>(t: &[T]) -> BytesMut {
421        let mut out1 = BytesMut::new();
422        encode_list(t, &mut out1);
423
424        let v = t.to_vec();
425        assert_eq!(out1.len(), v.length());
426
427        let mut out2 = BytesMut::new();
428        v.encode(&mut out2);
429        assert_eq!(out1, out2);
430
431        out1
432    }
433
434    fn encoded_iter<T: Encodable>(iter: impl Iterator<Item = T> + Clone) -> BytesMut {
435        let mut out = BytesMut::new();
436        encode_iter(iter, &mut out);
437        out
438    }
439
440    #[test]
441    fn rlp_str() {
442        assert_eq!(encode("")[..], hex!("80")[..]);
443        assert_eq!(encode("{")[..], hex!("7b")[..]);
444        assert_eq!(encode("test str")[..], hex!("887465737420737472")[..]);
445    }
446
447    #[test]
448    fn rlp_strings() {
449        assert_eq!(encode(hex!(""))[..], hex!("80")[..]);
450        assert_eq!(encode(hex!("7B"))[..], hex!("7b")[..]);
451        assert_eq!(encode(hex!("80"))[..], hex!("8180")[..]);
452        assert_eq!(encode(hex!("ABBA"))[..], hex!("82abba")[..]);
453    }
454
455    #[test]
456    fn rlp_bool() {
457        assert_eq!(encode(true), hex!("01"));
458        assert_eq!(encode(false), hex!("80"));
459    }
460
461    fn c<T, U: From<T>>(
462        it: impl IntoIterator<Item = (T, &'static [u8])>,
463    ) -> impl Iterator<Item = (U, &'static [u8])> {
464        it.into_iter().map(|(k, v)| (k.into(), v))
465    }
466
467    fn u8_fixtures() -> impl IntoIterator<Item = (u8, &'static [u8])> {
468        vec![
469            (0, &hex!("80")[..]),
470            (1, &hex!("01")[..]),
471            (0x7F, &hex!("7F")[..]),
472            (0x80, &hex!("8180")[..]),
473        ]
474    }
475
476    fn u16_fixtures() -> impl IntoIterator<Item = (u16, &'static [u8])> {
477        c(u8_fixtures()).chain(vec![(0x400, &hex!("820400")[..])])
478    }
479
480    fn u32_fixtures() -> impl IntoIterator<Item = (u32, &'static [u8])> {
481        c(u16_fixtures())
482            .chain(vec![(0xFFCCB5, &hex!("83ffccb5")[..]), (0xFFCCB5DD, &hex!("84ffccb5dd")[..])])
483    }
484
485    fn u64_fixtures() -> impl IntoIterator<Item = (u64, &'static [u8])> {
486        c(u32_fixtures()).chain(vec![
487            (0xFFCCB5DDFF, &hex!("85ffccb5ddff")[..]),
488            (0xFFCCB5DDFFEE, &hex!("86ffccb5ddffee")[..]),
489            (0xFFCCB5DDFFEE14, &hex!("87ffccb5ddffee14")[..]),
490            (0xFFCCB5DDFFEE1483, &hex!("88ffccb5ddffee1483")[..]),
491        ])
492    }
493
494    fn u128_fixtures() -> impl IntoIterator<Item = (u128, &'static [u8])> {
495        c(u64_fixtures()).chain(vec![(
496            0x10203E405060708090A0B0C0D0E0F2,
497            &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
498        )])
499    }
500
501    macro_rules! uint_rlp_test {
502        ($fixtures:expr) => {
503            for (input, output) in $fixtures {
504                assert_eq!(encode(input), output, "encode({input})");
505                #[cfg(feature = "arrayvec")]
506                assert_eq!(&encode_fixed_size(&input)[..], output, "encode_fixed_size({input})");
507            }
508        };
509    }
510
511    #[test]
512    fn rlp_uints() {
513        uint_rlp_test!(u8_fixtures());
514        uint_rlp_test!(u16_fixtures());
515        uint_rlp_test!(u32_fixtures());
516        uint_rlp_test!(u64_fixtures());
517        uint_rlp_test!(u128_fixtures());
518        // #[cfg(feature = "ethnum")]
519        // uint_rlp_test!(u256_fixtures());
520    }
521
522    #[test]
523    fn rlp_nonzero_uints() {
524        uint_rlp_test!([(NonZeroU8::new(1).unwrap(), &hex!("01")[..])]);
525        uint_rlp_test!([(NonZeroU16::new(0x400).unwrap(), &hex!("820400")[..])]);
526        uint_rlp_test!([(NonZeroU32::new(0xFFCCB5).unwrap(), &hex!("83ffccb5")[..])]);
527        uint_rlp_test!([(
528            NonZeroU64::new(0xFFCCB5DDFFEE1483).unwrap(),
529            &hex!("88ffccb5ddffee1483")[..]
530        )]);
531        uint_rlp_test!([(NonZeroUsize::new(0x80).unwrap(), &hex!("8180")[..])]);
532        uint_rlp_test!([(
533            NonZeroU128::new(0x10203E405060708090A0B0C0D0E0F2).unwrap(),
534            &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
535        )]);
536    }
537
538    /*
539    #[cfg(feature = "ethnum")]
540    fn u256_fixtures() -> impl IntoIterator<Item = (ethnum::U256, &'static [u8])> {
541        c(u128_fixtures()).chain(vec![(
542            ethnum::U256::from_str_radix(
543                "0100020003000400050006000700080009000A0B4B000C000D000E01",
544                16,
545            )
546            .unwrap(),
547            &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
548        )])
549    }
550
551    #[cfg(feature = "ethereum-types")]
552    fn eth_u64_fixtures() -> impl IntoIterator<Item = (ethereum_types::U64, &'static [u8])> {
553        c(u64_fixtures()).chain(vec![
554            (
555                ethereum_types::U64::from_str_radix("FFCCB5DDFF", 16).unwrap(),
556                &hex!("85ffccb5ddff")[..],
557            ),
558            (
559                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE", 16).unwrap(),
560                &hex!("86ffccb5ddffee")[..],
561            ),
562            (
563                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE14", 16).unwrap(),
564                &hex!("87ffccb5ddffee14")[..],
565            ),
566            (
567                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE1483", 16).unwrap(),
568                &hex!("88ffccb5ddffee1483")[..],
569            ),
570        ])
571    }
572
573    fn eth_u128_fixtures() -> impl IntoIterator<Item = (ethereum_types::U128, &'static [u8])> {
574        c(u128_fixtures()).chain(vec![(
575            ethereum_types::U128::from_str_radix("10203E405060708090A0B0C0D0E0F2", 16).unwrap(),
576            &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
577        )])
578    }
579
580    fn eth_u256_fixtures() -> impl IntoIterator<Item = (ethereum_types::U256, &'static [u8])> {
581        c(u128_fixtures()).chain(vec![(
582            ethereum_types::U256::from_str_radix(
583                "0100020003000400050006000700080009000A0B4B000C000D000E01",
584                16,
585            )
586            .unwrap(),
587            &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
588        )])
589    }
590
591    #[cfg(feature = "ethereum-types")]
592    fn eth_u512_fixtures() -> impl IntoIterator<Item = (ethereum_types::U512, &'static [u8])> {
593        c(eth_u256_fixtures()).chain(vec![(
594            ethereum_types::U512::from_str_radix(
595                "0100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01",
596                16,
597            )
598            .unwrap(),
599            &hex!("b8380100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01")[..],
600        )])
601    }
602
603    #[cfg(feature = "ethereum-types")]
604    #[test]
605    fn rlp_eth_uints() {
606        uint_rlp_test!(eth_u64_fixtures());
607        uint_rlp_test!(eth_u128_fixtures());
608        uint_rlp_test!(eth_u256_fixtures());
609        uint_rlp_test!(eth_u512_fixtures());
610    }
611    */
612
613    #[test]
614    fn rlp_list() {
615        assert_eq!(encoded_list::<u64>(&[]), &hex!("c0")[..]);
616        assert_eq!(encoded_list::<u8>(&[0x00u8]), &hex!("c180")[..]);
617        assert_eq!(encoded_list(&[0xFFCCB5_u64, 0xFFC0B5_u64]), &hex!("c883ffccb583ffc0b5")[..]);
618    }
619
620    #[test]
621    fn rlp_iter() {
622        assert_eq!(encoded_iter::<u64>([].into_iter()), &hex!("c0")[..]);
623        assert_eq!(
624            encoded_iter([0xFFCCB5_u64, 0xFFC0B5_u64].iter()),
625            &hex!("c883ffccb583ffc0b5")[..]
626        );
627    }
628
629    #[test]
630    fn to_be_bytes_trimmed() {
631        macro_rules! test_to_be_bytes_trimmed {
632            ($($x:expr => $expected:expr),+ $(,)?) => {$(
633                let be;
634                assert_eq!(to_be_bytes_trimmed!(be, $x), $expected);
635            )+};
636        }
637
638        test_to_be_bytes_trimmed! {
639            0u8 => [],
640            0u16 => [],
641            0u32 => [],
642            0u64 => [],
643            0usize => [],
644            0u128 => [],
645
646            1u8 => [1],
647            1u16 => [1],
648            1u32 => [1],
649            1u64 => [1],
650            1usize => [1],
651            1u128 => [1],
652
653            u8::MAX => [0xff],
654            u16::MAX => [0xff, 0xff],
655            u32::MAX => [0xff, 0xff, 0xff, 0xff],
656            u64::MAX => [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
657            u128::MAX => [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
658
659            1u8 => [1],
660            255u8 => [255],
661            256u16 => [1, 0],
662            65535u16 => [255, 255],
663            65536u32 => [1, 0, 0],
664            65536u64 => [1, 0, 0],
665        }
666    }
667}