#![cfg(feature = "rlp")]
#![cfg_attr(docsrs, doc(cfg(feature = "rlp")))]
use crate::{Bits, Uint};
use core::cmp::Ordering;
use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream};
impl<const BITS: usize, const LIMBS: usize> Encodable for Uint<BITS, LIMBS> {
fn rlp_append(&self, s: &mut RlpStream) {
let bytes = self.to_be_bytes_vec();
let bytes = trim_leading_zeros(&bytes);
bytes.rlp_append(s);
}
}
impl<const BITS: usize, const LIMBS: usize> Decodable for Uint<BITS, LIMBS> {
fn decode(s: &Rlp) -> Result<Self, DecoderError> {
Self::try_from_be_slice(s.data()?).ok_or(DecoderError::Custom(
"RLP integer value too large for Uint.",
))
}
}
impl<const BITS: usize, const LIMBS: usize> Encodable for Bits<BITS, LIMBS> {
#[allow(clippy::collection_is_never_read)] fn rlp_append(&self, s: &mut RlpStream) {
#[allow(clippy::collection_is_never_read)]
let bytes = self.to_be_bytes_vec();
bytes.rlp_append(s);
}
}
impl<const BITS: usize, const LIMBS: usize> Decodable for Bits<BITS, LIMBS> {
fn decode(s: &Rlp) -> Result<Self, DecoderError> {
s.decoder()
.decode_value(|bytes| match bytes.len().cmp(&Self::BYTES) {
Ordering::Less => Err(DecoderError::RlpIsTooShort),
Ordering::Greater => Err(DecoderError::RlpIsTooBig),
Ordering::Equal => Self::try_from_be_slice(bytes).ok_or(DecoderError::RlpIsTooBig),
})
}
}
fn trim_leading_zeros(bytes: &[u8]) -> &[u8] {
let zeros = bytes.iter().position(|&b| b != 0).unwrap_or(bytes.len());
&bytes[zeros..]
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
aliases::{B160, U0, U256},
const_for, nlimbs,
};
use hex_literal::hex;
use proptest::proptest;
#[test]
fn test_uint_rlp() {
assert_eq!(U0::from(0).rlp_bytes()[..], hex!("80"));
assert_eq!(U256::from(0).rlp_bytes()[..], hex!("80"));
assert_eq!(U256::from(15).rlp_bytes()[..], hex!("0f"));
assert_eq!(U256::from(1024).rlp_bytes()[..], hex!("820400"));
assert_eq!(U256::from(0x1234_5678).rlp_bytes()[..], hex!("8412345678"));
}
#[test]
fn test_uint_roundtrip() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
proptest!(|(value: Uint<BITS, LIMBS>)| {
let serialized = value.rlp_bytes();
let deserialized = Uint::decode(&Rlp::new(&serialized)).unwrap();
assert_eq!(value, deserialized);
});
});
}
#[test]
fn test_bits_rlp() {
assert_eq!(
"0xef2d6d194084c2de36e0dabfce45d046b37d1106"
.parse::<B160>()
.unwrap()
.rlp_bytes()[..],
hex!("94ef2d6d194084c2de36e0dabfce45d046b37d1106")
);
}
#[test]
fn test_bits_roundtrip() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
proptest!(|(value: Bits<BITS, LIMBS>)| {
let serialized = value.rlp_bytes();
let deserialized = Bits::decode(&Rlp::new(&serialized)).unwrap();
assert_eq!(value, deserialized);
});
});
}
}