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    [T: ?Sized + Encodable] alloc::sync::Arc<T>,
238}
239
240#[cfg(feature = "std")]
241mod std_support {
242    use super::*;
243    use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
244
245    impl Encodable for IpAddr {
246        #[inline]
247        fn length(&self) -> usize {
248            match self {
249                Self::V4(ip) => ip.length(),
250                Self::V6(ip) => ip.length(),
251            }
252        }
253
254        #[inline]
255        fn encode(&self, out: &mut dyn BufMut) {
256            match self {
257                Self::V4(ip) => ip.encode(out),
258                Self::V6(ip) => ip.encode(out),
259            }
260        }
261    }
262
263    impl Encodable for Ipv4Addr {
264        #[inline]
265        fn length(&self) -> usize {
266            self.octets().length()
267        }
268
269        #[inline]
270        fn encode(&self, out: &mut dyn BufMut) {
271            self.octets().encode(out)
272        }
273    }
274
275    impl Encodable for Ipv6Addr {
276        #[inline]
277        fn length(&self) -> usize {
278            self.octets().length()
279        }
280
281        #[inline]
282        fn encode(&self, out: &mut dyn BufMut) {
283            self.octets().encode(out)
284        }
285    }
286}
287
288/// Encode a value.
289///
290/// Prefer using [`encode_fixed_size`] if a type implements [`MaxEncodedLen`].
291#[inline]
292pub fn encode<T: Encodable>(value: T) -> Vec<u8> {
293    let mut out = Vec::with_capacity(value.length());
294    value.encode(&mut out);
295    out
296}
297
298/// Encode a type with a known maximum size.
299#[cfg(feature = "arrayvec")]
300#[inline]
301pub fn encode_fixed_size<T: MaxEncodedLen<LEN>, const LEN: usize>(value: &T) -> ArrayVec<u8, LEN> {
302    let mut vec = ArrayVec::<u8, LEN>::new();
303
304    // SAFETY: We're casting uninitalized memory to a slice of bytes to be written into.
305    let mut out = unsafe { core::slice::from_raw_parts_mut(vec.as_mut_ptr(), LEN) };
306    value.encode(&mut out);
307    let written = LEN - out.len();
308
309    // SAFETY: `written <= LEN` and all bytes are initialized.
310    unsafe { vec.set_len(written) };
311    vec
312}
313
314/// Calculate the length of a list.
315#[inline]
316pub fn list_length<B, T>(list: &[B]) -> usize
317where
318    B: Borrow<T>,
319    T: ?Sized + Encodable,
320{
321    let payload_length = rlp_list_header(list).payload_length;
322    payload_length + length_of_length(payload_length)
323}
324
325/// Encode a list of items.
326#[inline]
327pub fn encode_list<B, T>(values: &[B], out: &mut dyn BufMut)
328where
329    B: Borrow<T>,
330    T: ?Sized + Encodable,
331{
332    rlp_list_header(values).encode(out);
333    for value in values {
334        value.borrow().encode(out);
335    }
336}
337
338/// Encode all items from an iterator.
339///
340/// This clones the iterator. Prefer [`encode_list`] if possible.
341#[inline]
342pub fn encode_iter<I, B, T>(values: I, out: &mut dyn BufMut)
343where
344    I: Iterator<Item = B> + Clone,
345    B: Borrow<T>,
346    T: ?Sized + Encodable,
347{
348    let mut h = Header { list: true, payload_length: 0 };
349    for t in values.clone() {
350        h.payload_length += t.borrow().length();
351    }
352
353    h.encode(out);
354    for value in values {
355        value.borrow().encode(out);
356    }
357}
358
359/// Determine the length in bytes of the length prefix of an RLP item.
360#[inline]
361pub const fn length_of_length(payload_length: usize) -> usize {
362    if payload_length < 56 {
363        1
364    } else {
365        1 + (usize::BITS as usize / 8) - payload_length.leading_zeros() as usize / 8
366    }
367}
368
369#[inline]
370fn rlp_list_header<B, T>(values: &[B]) -> Header
371where
372    B: Borrow<T>,
373    T: ?Sized + Encodable,
374{
375    let mut h = Header { list: true, payload_length: 0 };
376    for value in values {
377        h.payload_length += value.borrow().length();
378    }
379    h
380}
381
382#[cfg(test)]
383mod tests {
384    use super::*;
385    use hex_literal::hex;
386
387    fn encoded_list<T: Encodable + Clone>(t: &[T]) -> BytesMut {
388        let mut out1 = BytesMut::new();
389        encode_list(t, &mut out1);
390
391        let v = t.to_vec();
392        assert_eq!(out1.len(), v.length());
393
394        let mut out2 = BytesMut::new();
395        v.encode(&mut out2);
396        assert_eq!(out1, out2);
397
398        out1
399    }
400
401    fn encoded_iter<T: Encodable>(iter: impl Iterator<Item = T> + Clone) -> BytesMut {
402        let mut out = BytesMut::new();
403        encode_iter(iter, &mut out);
404        out
405    }
406
407    #[test]
408    fn rlp_str() {
409        assert_eq!(encode("")[..], hex!("80")[..]);
410        assert_eq!(encode("{")[..], hex!("7b")[..]);
411        assert_eq!(encode("test str")[..], hex!("887465737420737472")[..]);
412    }
413
414    #[test]
415    fn rlp_strings() {
416        assert_eq!(encode(hex!(""))[..], hex!("80")[..]);
417        assert_eq!(encode(hex!("7B"))[..], hex!("7b")[..]);
418        assert_eq!(encode(hex!("80"))[..], hex!("8180")[..]);
419        assert_eq!(encode(hex!("ABBA"))[..], hex!("82abba")[..]);
420    }
421
422    #[test]
423    fn rlp_bool() {
424        assert_eq!(encode(true), hex!("01"));
425        assert_eq!(encode(false), hex!("80"));
426    }
427
428    fn c<T, U: From<T>>(
429        it: impl IntoIterator<Item = (T, &'static [u8])>,
430    ) -> impl Iterator<Item = (U, &'static [u8])> {
431        it.into_iter().map(|(k, v)| (k.into(), v))
432    }
433
434    fn u8_fixtures() -> impl IntoIterator<Item = (u8, &'static [u8])> {
435        vec![
436            (0, &hex!("80")[..]),
437            (1, &hex!("01")[..]),
438            (0x7F, &hex!("7F")[..]),
439            (0x80, &hex!("8180")[..]),
440        ]
441    }
442
443    fn u16_fixtures() -> impl IntoIterator<Item = (u16, &'static [u8])> {
444        c(u8_fixtures()).chain(vec![(0x400, &hex!("820400")[..])])
445    }
446
447    fn u32_fixtures() -> impl IntoIterator<Item = (u32, &'static [u8])> {
448        c(u16_fixtures())
449            .chain(vec![(0xFFCCB5, &hex!("83ffccb5")[..]), (0xFFCCB5DD, &hex!("84ffccb5dd")[..])])
450    }
451
452    fn u64_fixtures() -> impl IntoIterator<Item = (u64, &'static [u8])> {
453        c(u32_fixtures()).chain(vec![
454            (0xFFCCB5DDFF, &hex!("85ffccb5ddff")[..]),
455            (0xFFCCB5DDFFEE, &hex!("86ffccb5ddffee")[..]),
456            (0xFFCCB5DDFFEE14, &hex!("87ffccb5ddffee14")[..]),
457            (0xFFCCB5DDFFEE1483, &hex!("88ffccb5ddffee1483")[..]),
458        ])
459    }
460
461    fn u128_fixtures() -> impl IntoIterator<Item = (u128, &'static [u8])> {
462        c(u64_fixtures()).chain(vec![(
463            0x10203E405060708090A0B0C0D0E0F2,
464            &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
465        )])
466    }
467
468    macro_rules! uint_rlp_test {
469        ($fixtures:expr) => {
470            for (input, output) in $fixtures {
471                assert_eq!(encode(input), output, "encode({input})");
472                #[cfg(feature = "arrayvec")]
473                assert_eq!(&encode_fixed_size(&input)[..], output, "encode_fixed_size({input})");
474            }
475        };
476    }
477
478    #[test]
479    fn rlp_uints() {
480        uint_rlp_test!(u8_fixtures());
481        uint_rlp_test!(u16_fixtures());
482        uint_rlp_test!(u32_fixtures());
483        uint_rlp_test!(u64_fixtures());
484        uint_rlp_test!(u128_fixtures());
485        // #[cfg(feature = "ethnum")]
486        // uint_rlp_test!(u256_fixtures());
487    }
488
489    /*
490    #[cfg(feature = "ethnum")]
491    fn u256_fixtures() -> impl IntoIterator<Item = (ethnum::U256, &'static [u8])> {
492        c(u128_fixtures()).chain(vec![(
493            ethnum::U256::from_str_radix(
494                "0100020003000400050006000700080009000A0B4B000C000D000E01",
495                16,
496            )
497            .unwrap(),
498            &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
499        )])
500    }
501
502    #[cfg(feature = "ethereum-types")]
503    fn eth_u64_fixtures() -> impl IntoIterator<Item = (ethereum_types::U64, &'static [u8])> {
504        c(u64_fixtures()).chain(vec![
505            (
506                ethereum_types::U64::from_str_radix("FFCCB5DDFF", 16).unwrap(),
507                &hex!("85ffccb5ddff")[..],
508            ),
509            (
510                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE", 16).unwrap(),
511                &hex!("86ffccb5ddffee")[..],
512            ),
513            (
514                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE14", 16).unwrap(),
515                &hex!("87ffccb5ddffee14")[..],
516            ),
517            (
518                ethereum_types::U64::from_str_radix("FFCCB5DDFFEE1483", 16).unwrap(),
519                &hex!("88ffccb5ddffee1483")[..],
520            ),
521        ])
522    }
523
524    fn eth_u128_fixtures() -> impl IntoIterator<Item = (ethereum_types::U128, &'static [u8])> {
525        c(u128_fixtures()).chain(vec![(
526            ethereum_types::U128::from_str_radix("10203E405060708090A0B0C0D0E0F2", 16).unwrap(),
527            &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
528        )])
529    }
530
531    fn eth_u256_fixtures() -> impl IntoIterator<Item = (ethereum_types::U256, &'static [u8])> {
532        c(u128_fixtures()).chain(vec![(
533            ethereum_types::U256::from_str_radix(
534                "0100020003000400050006000700080009000A0B4B000C000D000E01",
535                16,
536            )
537            .unwrap(),
538            &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
539        )])
540    }
541
542    #[cfg(feature = "ethereum-types")]
543    fn eth_u512_fixtures() -> impl IntoIterator<Item = (ethereum_types::U512, &'static [u8])> {
544        c(eth_u256_fixtures()).chain(vec![(
545            ethereum_types::U512::from_str_radix(
546                "0100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01",
547                16,
548            )
549            .unwrap(),
550            &hex!("b8380100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01")[..],
551        )])
552    }
553
554    #[cfg(feature = "ethereum-types")]
555    #[test]
556    fn rlp_eth_uints() {
557        uint_rlp_test!(eth_u64_fixtures());
558        uint_rlp_test!(eth_u128_fixtures());
559        uint_rlp_test!(eth_u256_fixtures());
560        uint_rlp_test!(eth_u512_fixtures());
561    }
562    */
563
564    #[test]
565    fn rlp_list() {
566        assert_eq!(encoded_list::<u64>(&[]), &hex!("c0")[..]);
567        assert_eq!(encoded_list::<u8>(&[0x00u8]), &hex!("c180")[..]);
568        assert_eq!(encoded_list(&[0xFFCCB5_u64, 0xFFC0B5_u64]), &hex!("c883ffccb583ffc0b5")[..]);
569    }
570
571    #[test]
572    fn rlp_iter() {
573        assert_eq!(encoded_iter::<u64>([].into_iter()), &hex!("c0")[..]);
574        assert_eq!(
575            encoded_iter([0xFFCCB5_u64, 0xFFC0B5_u64].iter()),
576            &hex!("c883ffccb583ffc0b5")[..]
577        );
578    }
579
580    #[test]
581    fn to_be_bytes_trimmed() {
582        macro_rules! test_to_be_bytes_trimmed {
583            ($($x:expr => $expected:expr),+ $(,)?) => {$(
584                let be;
585                assert_eq!(to_be_bytes_trimmed!(be, $x), $expected);
586            )+};
587        }
588
589        test_to_be_bytes_trimmed! {
590            0u8 => [],
591            0u16 => [],
592            0u32 => [],
593            0u64 => [],
594            0usize => [],
595            0u128 => [],
596
597            1u8 => [1],
598            1u16 => [1],
599            1u32 => [1],
600            1u64 => [1],
601            1usize => [1],
602            1u128 => [1],
603
604            u8::MAX => [0xff],
605            u16::MAX => [0xff, 0xff],
606            u32::MAX => [0xff, 0xff, 0xff, 0xff],
607            u64::MAX => [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
608            u128::MAX => [0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff],
609
610            1u8 => [1],
611            255u8 => [255],
612            256u16 => [1, 0],
613            65535u16 => [255, 255],
614            65536u32 => [1, 0, 0],
615            65536u64 => [1, 0, 0],
616        }
617    }
618}