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