1use crate::types::*;
2use arrayvec::ArrayVec;
3use auto_impl::auto_impl;
4use bytes::{BufMut, Bytes, BytesMut};
5use core::borrow::Borrow;
6
7fn zeroless_view(v: &impl AsRef<[u8]>) -> &[u8] {
8 let v = v.as_ref();
9 &v[v.iter().take_while(|&&b| b == 0).count()..]
10}
11
12impl Header {
13 pub fn encode(&self, out: &mut dyn BufMut) {
15 if self.payload_length < 56 {
16 let code = if self.list { EMPTY_LIST_CODE } else { EMPTY_STRING_CODE };
17 out.put_u8(code + self.payload_length as u8);
18 } else {
19 let len_be = self.payload_length.to_be_bytes();
20 let len_be = zeroless_view(&len_be);
21 let code = if self.list { 0xF7 } else { 0xB7 };
22 out.put_u8(code + len_be.len() as u8);
23 out.put_slice(len_be);
24 }
25 }
26
27 pub fn length(&self) -> usize {
29 let mut out = BytesMut::new();
30 self.encode(&mut out);
31 out.len()
32 }
33}
34
35pub const fn length_of_length(payload_length: usize) -> usize {
36 if payload_length < 56 {
37 1
38 } else {
39 1 + 8 - payload_length.leading_zeros() as usize / 8
40 }
41}
42
43#[doc(hidden)]
44pub const fn const_add(a: usize, b: usize) -> usize {
45 a + b
46}
47
48#[doc(hidden)]
49pub unsafe trait MaxEncodedLen<const LEN: usize>: Encodable {}
50
51#[doc(hidden)]
52pub unsafe trait MaxEncodedLenAssoc: Encodable {
53 const LEN: usize;
54}
55
56#[macro_export]
61macro_rules! impl_max_encoded_len {
62 ($t:ty, $len:block) => {
63 unsafe impl MaxEncodedLen<{ $len }> for $t {}
64 unsafe impl MaxEncodedLenAssoc for $t {
65 const LEN: usize = $len;
66 }
67 };
68}
69
70#[auto_impl(&)]
71#[cfg_attr(feature = "alloc", auto_impl(Box, Arc))]
72pub trait Encodable {
73 fn encode(&self, out: &mut dyn BufMut);
74 fn length(&self) -> usize {
75 let mut out = BytesMut::new();
76 self.encode(&mut out);
77 out.len()
78 }
79}
80
81impl<'a> Encodable for &'a [u8] {
82 fn length(&self) -> usize {
83 let mut len = self.len();
84 if self.len() != 1 || self[0] >= EMPTY_STRING_CODE {
85 len += length_of_length(self.len());
86 }
87 len
88 }
89
90 fn encode(&self, out: &mut dyn BufMut) {
91 if self.len() != 1 || self[0] >= EMPTY_STRING_CODE {
92 Header { list: false, payload_length: self.len() }.encode(out);
93 }
94 out.put_slice(self);
95 }
96}
97
98impl<const LEN: usize> Encodable for [u8; LEN] {
99 fn length(&self) -> usize {
100 (self as &[u8]).length()
101 }
102
103 fn encode(&self, out: &mut dyn BufMut) {
104 (self as &[u8]).encode(out)
105 }
106}
107
108unsafe impl<const LEN: usize> MaxEncodedLenAssoc for [u8; LEN] {
109 const LEN: usize = LEN + length_of_length(LEN);
110}
111
112macro_rules! encodable_uint {
113 ($t:ty) => {
114 #[allow(clippy::cmp_owned)]
115 impl Encodable for $t {
116 fn length(&self) -> usize {
117 if *self < <$t>::from(EMPTY_STRING_CODE) {
118 1
119 } else {
120 1 + (<$t>::BITS as usize / 8) - (self.leading_zeros() as usize / 8)
121 }
122 }
123
124 fn encode(&self, out: &mut dyn BufMut) {
125 if *self == 0 {
126 out.put_u8(EMPTY_STRING_CODE);
127 } else if *self < <$t>::from(EMPTY_STRING_CODE) {
128 out.put_u8(u8::try_from(*self).unwrap());
129 } else {
130 let be = self.to_be_bytes();
131 let be = zeroless_view(&be);
132 out.put_u8(EMPTY_STRING_CODE + be.len() as u8);
133 out.put_slice(be);
134 }
135 }
136 }
137 };
138}
139
140macro_rules! max_encoded_len_uint {
141 ($t:ty) => {
142 impl_max_encoded_len!($t, {
143 length_of_length(<$t>::MAX.to_be_bytes().len()) + <$t>::MAX.to_be_bytes().len()
144 });
145 };
146}
147
148encodable_uint!(usize);
149max_encoded_len_uint!(usize);
150
151encodable_uint!(u8);
152max_encoded_len_uint!(u8);
153
154encodable_uint!(u16);
155max_encoded_len_uint!(u16);
156
157encodable_uint!(u32);
158max_encoded_len_uint!(u32);
159
160encodable_uint!(u64);
161max_encoded_len_uint!(u64);
162
163encodable_uint!(u128);
164max_encoded_len_uint!(u128);
165
166impl Encodable for bool {
167 fn length(&self) -> usize {
168 (*self as u8).length()
169 }
170
171 fn encode(&self, out: &mut dyn BufMut) {
172 (*self as u8).encode(out)
173 }
174}
175
176impl_max_encoded_len!(bool, { <u8 as MaxEncodedLenAssoc>::LEN });
177
178#[cfg(feature = "ethnum")]
179mod ethnum_support {
180 use super::*;
181
182 encodable_uint!(ethnum::U256);
183 impl_max_encoded_len!(ethnum::U256, { length_of_length(32) + 32 });
184}
185
186#[cfg(feature = "ethereum-types")]
187mod ethereum_types_support {
188 use super::*;
189 use ethereum_types::*;
190
191 macro_rules! fixed_hash_impl {
192 ($t:ty) => {
193 impl Encodable for $t {
194 fn length(&self) -> usize {
195 self.0.length()
196 }
197
198 fn encode(&self, out: &mut dyn bytes::BufMut) {
199 self.0.encode(out)
200 }
201 }
202 impl_max_encoded_len!($t, { length_of_length(<$t>::len_bytes()) + <$t>::len_bytes() });
203 };
204 }
205
206 fixed_hash_impl!(H64);
207 fixed_hash_impl!(H128);
208 fixed_hash_impl!(H160);
209 fixed_hash_impl!(H256);
210 fixed_hash_impl!(H512);
211 fixed_hash_impl!(H520);
212 fixed_hash_impl!(Bloom);
213
214 macro_rules! fixed_uint_impl {
215 ($t:ty, $n_bytes:tt) => {
216 impl Encodable for $t {
217 fn length(&self) -> usize {
218 if *self < <$t>::from(EMPTY_STRING_CODE) {
219 1
220 } else {
221 1 + $n_bytes - (self.leading_zeros() as usize / 8)
222 }
223 }
224
225 fn encode(&self, out: &mut dyn bytes::BufMut) {
226 let mut temp_arr = [0u8; $n_bytes];
227 self.to_big_endian(&mut temp_arr[..]);
228 let sliced = &temp_arr[(self.leading_zeros() / 8) as usize..];
230 sliced.encode(out);
231 }
232 }
233 };
234 }
235
236 fixed_uint_impl!(U64, 8);
237 fixed_uint_impl!(U128, 16);
238 fixed_uint_impl!(U256, 32);
239 fixed_uint_impl!(U512, 64);
240}
241
242macro_rules! slice_impl {
243 ($t:ty) => {
244 impl $crate::Encodable for $t {
245 fn length(&self) -> usize {
246 (&self[..]).length()
247 }
248
249 fn encode(&self, out: &mut dyn bytes::BufMut) {
250 (&self[..]).encode(out)
251 }
252 }
253 };
254}
255
256#[cfg(feature = "alloc")]
257mod alloc_support {
258 use super::*;
259
260 extern crate alloc;
261
262 impl<T> Encodable for ::alloc::vec::Vec<T>
263 where
264 T: Encodable,
265 {
266 fn length(&self) -> usize {
267 list_length(self)
268 }
269
270 fn encode(&self, out: &mut dyn BufMut) {
271 encode_list(self, out)
272 }
273 }
274
275 impl Encodable for ::alloc::string::String {
276 fn encode(&self, out: &mut dyn BufMut) {
277 self.as_bytes().encode(out);
278 }
279 fn length(&self) -> usize {
280 self.as_bytes().length()
281 }
282 }
283}
284slice_impl!(Bytes);
285slice_impl!(BytesMut);
286
287fn rlp_list_header<E, K>(v: &[K]) -> Header
288where
289 E: Encodable + ?Sized,
290 K: Borrow<E>,
291{
292 let mut h = Header { list: true, payload_length: 0 };
293 for x in v {
294 h.payload_length += x.borrow().length();
295 }
296 h
297}
298
299pub fn list_length<E, K>(v: &[K]) -> usize
300where
301 E: Encodable,
302 K: Borrow<E>,
303{
304 let payload_length = rlp_list_header(v).payload_length;
305 length_of_length(payload_length) + payload_length
306}
307
308pub fn encode_list<E, K>(v: &[K], out: &mut dyn BufMut)
309where
310 E: Encodable + ?Sized,
311 K: Borrow<E>,
312{
313 let h = rlp_list_header(v);
314 h.encode(out);
315 for x in v {
316 x.borrow().encode(out);
317 }
318}
319
320pub fn encode_fixed_size<E: MaxEncodedLen<LEN>, const LEN: usize>(v: &E) -> ArrayVec<u8, LEN> {
321 let mut out = ArrayVec::from([0_u8; LEN]);
322
323 let mut s = out.as_mut_slice();
324
325 v.encode(&mut s);
326
327 let final_len = LEN - s.len();
328 out.truncate(final_len);
329
330 out
331}
332
333#[cfg(test)]
334mod tests {
335 extern crate alloc;
336
337 use super::*;
338 use alloc::vec;
339 use bytes::BytesMut;
340 use hex_literal::hex;
341
342 fn encoded<T: Encodable>(t: T) -> BytesMut {
343 let mut out = BytesMut::new();
344 t.encode(&mut out);
345 out
346 }
347
348 fn encoded_list<T: Encodable + Clone>(t: &[T]) -> BytesMut {
349 let mut out1 = BytesMut::new();
350 encode_list(t, &mut out1);
351
352 let v = t.to_vec();
353 assert_eq!(out1.len(), v.length());
354
355 let mut out2 = BytesMut::new();
356 v.encode(&mut out2);
357 assert_eq!(out1, out2);
358
359 out1
360 }
361
362 #[test]
363 fn rlp_strings() {
364 assert_eq!(encoded(hex!(""))[..], hex!("80")[..]);
365 assert_eq!(encoded(hex!("7B"))[..], hex!("7b")[..]);
366 assert_eq!(encoded(hex!("80"))[..], hex!("8180")[..]);
367 assert_eq!(encoded(hex!("ABBA"))[..], hex!("82abba")[..]);
368 }
369
370 fn u8_fixtures() -> impl IntoIterator<Item = (u8, &'static [u8])> {
371 vec![
372 (0, &hex!("80")[..]),
373 (1, &hex!("01")[..]),
374 (0x7F, &hex!("7F")[..]),
375 (0x80, &hex!("8180")[..]),
376 ]
377 }
378
379 fn c<T, U: From<T>>(
380 it: impl IntoIterator<Item = (T, &'static [u8])>,
381 ) -> impl Iterator<Item = (U, &'static [u8])> {
382 it.into_iter().map(|(k, v)| (k.into(), v))
383 }
384
385 fn u16_fixtures() -> impl IntoIterator<Item = (u16, &'static [u8])> {
386 c(u8_fixtures()).chain(vec![(0x400, &hex!("820400")[..])])
387 }
388
389 fn u32_fixtures() -> impl IntoIterator<Item = (u32, &'static [u8])> {
390 c(u16_fixtures())
391 .chain(vec![(0xFFCCB5, &hex!("83ffccb5")[..]), (0xFFCCB5DD, &hex!("84ffccb5dd")[..])])
392 }
393
394 fn u64_fixtures() -> impl IntoIterator<Item = (u64, &'static [u8])> {
395 c(u32_fixtures()).chain(vec![
396 (0xFFCCB5DDFF, &hex!("85ffccb5ddff")[..]),
397 (0xFFCCB5DDFFEE, &hex!("86ffccb5ddffee")[..]),
398 (0xFFCCB5DDFFEE14, &hex!("87ffccb5ddffee14")[..]),
399 (0xFFCCB5DDFFEE1483, &hex!("88ffccb5ddffee1483")[..]),
400 ])
401 }
402
403 fn u128_fixtures() -> impl IntoIterator<Item = (u128, &'static [u8])> {
404 c(u64_fixtures()).chain(vec![(
405 0x10203E405060708090A0B0C0D0E0F2,
406 &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
407 )])
408 }
409
410 #[cfg(feature = "ethnum")]
411 fn u256_fixtures() -> impl IntoIterator<Item = (ethnum::U256, &'static [u8])> {
412 c(u128_fixtures()).chain(vec![(
413 ethnum::U256::from_str_radix(
414 "0100020003000400050006000700080009000A0B4B000C000D000E01",
415 16,
416 )
417 .unwrap(),
418 &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
419 )])
420 }
421
422 #[cfg(feature = "ethereum-types")]
423 fn eth_u64_fixtures() -> impl IntoIterator<Item = (ethereum_types::U64, &'static [u8])> {
424 c(u64_fixtures()).chain(vec![
425 (
426 ethereum_types::U64::from_str_radix("FFCCB5DDFF", 16).unwrap(),
427 &hex!("85ffccb5ddff")[..],
428 ),
429 (
430 ethereum_types::U64::from_str_radix("FFCCB5DDFFEE", 16).unwrap(),
431 &hex!("86ffccb5ddffee")[..],
432 ),
433 (
434 ethereum_types::U64::from_str_radix("FFCCB5DDFFEE14", 16).unwrap(),
435 &hex!("87ffccb5ddffee14")[..],
436 ),
437 (
438 ethereum_types::U64::from_str_radix("FFCCB5DDFFEE1483", 16).unwrap(),
439 &hex!("88ffccb5ddffee1483")[..],
440 ),
441 ])
442 }
443
444 #[cfg(feature = "ethereum-types")]
445 fn eth_u128_fixtures() -> impl IntoIterator<Item = (ethereum_types::U128, &'static [u8])> {
446 c(u128_fixtures()).chain(vec![(
447 ethereum_types::U128::from_str_radix("10203E405060708090A0B0C0D0E0F2", 16).unwrap(),
448 &hex!("8f10203e405060708090a0b0c0d0e0f2")[..],
449 )])
450 }
451
452 #[cfg(feature = "ethereum-types")]
453 fn eth_u256_fixtures() -> impl IntoIterator<Item = (ethereum_types::U256, &'static [u8])> {
454 c(u128_fixtures()).chain(vec![(
455 ethereum_types::U256::from_str_radix(
456 "0100020003000400050006000700080009000A0B4B000C000D000E01",
457 16,
458 )
459 .unwrap(),
460 &hex!("9c0100020003000400050006000700080009000a0b4b000c000d000e01")[..],
461 )])
462 }
463
464 #[cfg(feature = "ethereum-types")]
465 fn eth_u512_fixtures() -> impl IntoIterator<Item = (ethereum_types::U512, &'static [u8])> {
466 c(eth_u256_fixtures()).chain(vec![(
467 ethereum_types::U512::from_str_radix(
468 "0100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01",
469 16,
470 )
471 .unwrap(),
472 &hex!("b8380100020003000400050006000700080009000A0B4B000C000D000E010100020003000400050006000700080009000A0B4B000C000D000E01")[..],
473 )])
474 }
475
476 macro_rules! uint_rlp_test {
477 ($fixtures:expr) => {
478 for (input, output) in $fixtures {
479 assert_eq!(encoded(input), output);
480 }
481 };
482 }
483
484 #[test]
485 fn rlp_uints() {
486 uint_rlp_test!(u8_fixtures());
487 uint_rlp_test!(u16_fixtures());
488 uint_rlp_test!(u32_fixtures());
489 uint_rlp_test!(u64_fixtures());
490 uint_rlp_test!(u128_fixtures());
491 #[cfg(feature = "ethnum")]
492 uint_rlp_test!(u256_fixtures());
493 }
494
495 #[cfg(feature = "ethereum-types")]
496 #[test]
497 fn rlp_eth_uints() {
498 uint_rlp_test!(eth_u64_fixtures());
499 uint_rlp_test!(eth_u128_fixtures());
500 uint_rlp_test!(eth_u256_fixtures());
501 uint_rlp_test!(eth_u512_fixtures());
502 }
503
504 #[test]
505 fn rlp_list() {
506 assert_eq!(encoded_list::<u64>(&[]), &hex!("c0")[..]);
507 assert_eq!(encoded_list(&[0xFFCCB5_u64, 0xFFC0B5_u64]), &hex!("c883ffccb583ffc0b5")[..]);
508 }
509}