1use alloy_primitives::{hex, keccak256, B256};
2use alloy_rlp::EMPTY_STRING_CODE;
3use arrayvec::ArrayVec;
4use core::fmt;
5
6const MAX: usize = 33;
7
8#[derive(Clone, Default, PartialEq, Eq)]
10#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
11pub struct RlpNode(ArrayVec<u8, MAX>);
12
13impl alloy_rlp::Decodable for RlpNode {
14 fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
15 let bytes = alloy_rlp::Header::decode_bytes(buf, false)?;
16 Self::from_raw_rlp(bytes)
17 }
18}
19
20impl core::ops::Deref for RlpNode {
21 type Target = [u8];
22
23 #[inline]
24 fn deref(&self) -> &Self::Target {
25 &self.0
26 }
27}
28
29impl core::ops::DerefMut for RlpNode {
30 #[inline]
31 fn deref_mut(&mut self) -> &mut Self::Target {
32 &mut self.0
33 }
34}
35
36impl AsRef<[u8]> for RlpNode {
37 #[inline]
38 fn as_ref(&self) -> &[u8] {
39 &self.0
40 }
41}
42
43impl fmt::Debug for RlpNode {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 write!(f, "RlpNode({})", hex::encode_prefixed(&self.0))
46 }
47}
48
49impl RlpNode {
50 #[inline]
54 pub fn from_raw(data: &[u8]) -> Option<Self> {
55 let mut arr = ArrayVec::new();
56 arr.try_extend_from_slice(data).ok()?;
57 Some(Self(arr))
58 }
59
60 #[inline]
62 pub fn from_raw_rlp(data: &[u8]) -> alloy_rlp::Result<Self> {
63 Self::from_raw(data).ok_or(alloy_rlp::Error::Custom("RLP node too large"))
64 }
65
66 #[doc(alias = "rlp_node")]
68 #[inline]
69 pub fn from_rlp(rlp: &[u8]) -> Self {
70 if rlp.len() < 32 {
71 unsafe { Self::from_raw(rlp).unwrap_unchecked() }
73 } else {
74 Self::word_rlp(&keccak256(rlp))
75 }
76 }
77
78 #[inline]
80 pub fn word_rlp(word: &B256) -> Self {
81 let mut arr = [0u8; 33];
82 arr[0] = EMPTY_STRING_CODE + 32;
83 arr[1..].copy_from_slice(word.as_slice());
84 Self(ArrayVec::from(arr))
85 }
86
87 #[inline]
89 pub fn is_hash(&self) -> bool {
90 self.len() == B256::len_bytes() + 1
91 }
92
93 #[inline]
95 pub fn as_slice(&self) -> &[u8] {
96 &self.0
97 }
98
99 #[inline]
101 pub fn as_hash(&self) -> Option<B256> {
102 if self.is_hash() {
103 Some(B256::from_slice(&self.0[1..]))
104 } else {
105 None
106 }
107 }
108}
109
110#[cfg(feature = "arbitrary")]
111impl<'u> arbitrary::Arbitrary<'u> for RlpNode {
112 fn arbitrary(g: &mut arbitrary::Unstructured<'u>) -> arbitrary::Result<Self> {
113 let len = g.int_in_range(0..=MAX)?;
114 let mut arr = ArrayVec::new();
115 arr.try_extend_from_slice(g.bytes(len)?).unwrap();
116 Ok(Self(arr))
117 }
118}
119
120#[cfg(feature = "arbitrary")]
121impl proptest::arbitrary::Arbitrary for RlpNode {
122 type Parameters = ();
123 type Strategy = proptest::strategy::BoxedStrategy<Self>;
124
125 fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
126 use proptest::prelude::*;
127 proptest::collection::vec(proptest::prelude::any::<u8>(), 0..=MAX)
128 .prop_map(|vec| Self::from_raw(&vec).unwrap())
129 .boxed()
130 }
131}