use alloy_primitives::{hex, keccak256, B256};
use alloy_rlp::EMPTY_STRING_CODE;
use arrayvec::ArrayVec;
use core::fmt;
const MAX: usize = 33;
#[derive(Clone, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct RlpNode(ArrayVec<u8, MAX>);
impl alloy_rlp::Decodable for RlpNode {
fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
let bytes = alloy_rlp::Header::decode_bytes(buf, false)?;
Self::from_raw_rlp(bytes)
}
}
impl core::ops::Deref for RlpNode {
type Target = [u8];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl core::ops::DerefMut for RlpNode {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl AsRef<[u8]> for RlpNode {
#[inline]
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl fmt::Debug for RlpNode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "RlpNode({})", hex::encode_prefixed(&self.0))
}
}
impl RlpNode {
#[inline]
pub fn from_raw(data: &[u8]) -> Option<Self> {
let mut arr = ArrayVec::new();
arr.try_extend_from_slice(data).ok()?;
Some(Self(arr))
}
#[inline]
pub fn from_raw_rlp(data: &[u8]) -> alloy_rlp::Result<Self> {
Self::from_raw(data).ok_or(alloy_rlp::Error::Custom("RLP node too large"))
}
#[doc(alias = "rlp_node")]
#[inline]
pub fn from_rlp(rlp: &[u8]) -> Self {
if rlp.len() < 32 {
unsafe { Self::from_raw(rlp).unwrap_unchecked() }
} else {
Self::word_rlp(&keccak256(rlp))
}
}
#[inline]
pub fn word_rlp(word: &B256) -> Self {
let mut arr = ArrayVec::new();
arr.push(EMPTY_STRING_CODE + 32);
arr.try_extend_from_slice(word.as_slice()).unwrap();
Self(arr)
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.0
}
#[inline]
pub fn as_hash(&self) -> Option<B256> {
if self.len() == B256::len_bytes() + 1 {
Some(B256::from_slice(&self.0[1..]))
} else {
None
}
}
}
#[cfg(feature = "arbitrary")]
impl<'u> arbitrary::Arbitrary<'u> for RlpNode {
fn arbitrary(g: &mut arbitrary::Unstructured<'u>) -> arbitrary::Result<Self> {
let len = g.int_in_range(0..=MAX)?;
let mut arr = ArrayVec::new();
arr.try_extend_from_slice(g.bytes(len)?).unwrap();
Ok(Self(arr))
}
}
#[cfg(feature = "arbitrary")]
impl proptest::arbitrary::Arbitrary for RlpNode {
type Parameters = ();
type Strategy = proptest::strategy::BoxedStrategy<Self>;
fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
use proptest::prelude::*;
proptest::collection::vec(proptest::prelude::any::<u8>(), 0..=MAX)
.prop_map(|vec| Self::from_raw(&vec).unwrap())
.boxed()
}
}