pub use bytes::{Buf, BufMut, Bytes, BytesMut};
pub use fastrlp::{Decodable, DecodeError as RLPError, Encodable, Header};
pub type RLPResult<T> = Result<T, RLPError>;
#[doc(hidden)]
#[macro_export]
macro_rules! __encode_as {
($out:expr, $field:expr) => {
$field.encode($out);
};
($out:expr, $field:expr => $cast:ty) => {
<$cast>::from($field.clone()).encode($out);
};
($out:expr, $field:expr $(=> $cast:ty)?, $($fields:expr $(=> $casts:ty)?),+) => {
$crate::__encode_as! { $out, $field $(=> $cast)? }
$crate::__encode_as! { $out, $($fields $(=> $casts)?),+ }
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __decode_as {
($buf:expr, $field:ty) => {
<$field>::decode($buf)?
};
($buf:expr, $field:ty => $cast:ty) => {
<$field>::from(<$cast>::decode($buf)?)
};
($buf:expr, $field:ty $(=> $cast:ty)?, $($fields:ty $(=> $casts:ty)?),+) => {
$crate::__decode_as! { $buf, $field $(=> $cast)? }
$crate::__decode_as! { $buf, $($fields $(=> $casts)?),+ }
};
}
#[macro_export]
macro_rules! rlp_encodable {
(
$(#[$attr:meta])*
$vis:vis struct $name:ident {
$(
$(#[$field_attr:meta])*
$field_vis:vis $field_name:ident: $field_type:ty $(=> $cast:ty)?,
)*
}
) => {
$(#[$attr])*
$vis struct $name {
$(
$(#[$field_attr])*
$field_vis $field_name: $field_type,
)*
}
impl $name {
fn encode_internal(&self, out: &mut dyn $crate::rlp::BufMut) {
use $crate::rlp::Encodable;
$crate::__encode_as!(out, $(self.$field_name $(=> $cast)?),+);
}
}
impl $crate::rlp::Encodable for $name {
fn encode(&self, out: &mut dyn $crate::rlp::BufMut) {
let mut buf = $crate::rlp::BytesMut::new();
self.encode_internal(&mut buf);
$crate::rlp::Header {
list: true,
payload_length: buf.len()
}.encode(out);
out.put_slice(&buf)
}
}
impl $crate::rlp::Decodable for $name {
fn decode(buf: &mut &[u8]) -> $crate::rlp::RLPResult<Self> {
#[allow(unused_imports)]
use $crate::rlp::Decodable;
$crate::rlp::Header::decode(buf)?;
Ok(Self {
$($field_name: $crate::__decode_as!(buf, $field_type $(=> $cast)? )),*
})
}
}
}
}
macro_rules! map_to_option {
($name:ident) => {
impl<T: Encodable + Decodable, S: Into<T>> From<Option<S>> for $name<T> {
fn from(value: Option<S>) -> Self {
match value {
Some(v) => Self::Just(v.into()),
None => Self::Nothing,
}
}
}
impl<T: Encodable + Decodable> From<$name<T>> for Option<T> {
fn from(value: $name<T>) -> Self {
match value {
$name::Just(v) => Self::Some(v),
$name::Nothing => Self::None,
}
}
}
};
}
#[allow(clippy::manual_non_exhaustive)]
pub enum AsBytes<T: Encodable + Decodable> {
#[doc(hidden)]
Just(T),
#[doc(hidden)]
Nothing,
}
map_to_option!(AsBytes);
impl<T: Encodable + Decodable> Encodable for AsBytes<T> {
fn encode(&self, out: &mut dyn BufMut) {
match self {
Self::Just(value) => value.encode(out),
Self::Nothing => Bytes::new().encode(out),
}
}
}
impl<T: Encodable + Decodable> Decodable for AsBytes<T> {
fn decode(buf: &mut &[u8]) -> RLPResult<Self> {
if buf[0] == fastrlp::EMPTY_STRING_CODE {
Bytes::decode(buf)?;
Ok(Self::Nothing)
} else {
Ok(Self::Just(T::decode(buf)?))
}
}
}
#[allow(clippy::manual_non_exhaustive)]
pub enum AsVec<T: Encodable + Decodable> {
#[doc(hidden)]
Just(T),
#[doc(hidden)]
Nothing,
}
map_to_option!(AsVec);
impl<T: Encodable + Decodable> Encodable for AsVec<T> {
fn encode(&self, out: &mut dyn BufMut) {
match self {
Self::Just(value) => value.encode(out),
Self::Nothing => fastrlp::Header {
list: true,
payload_length: 0,
}
.encode(out),
}
}
}
impl<T: Encodable + Decodable> Decodable for AsVec<T> {
fn decode(buf: &mut &[u8]) -> RLPResult<Self> {
if buf[0] == fastrlp::EMPTY_LIST_CODE {
let header = fastrlp::Header::decode(buf)?;
debug_assert!(header.list);
debug_assert!(header.payload_length == 0);
Ok(Self::Nothing)
} else {
Ok(Self::Just(T::decode(buf)?))
}
}
}
#[allow(clippy::manual_non_exhaustive)]
pub enum Maybe<T: Encodable + Decodable> {
#[doc(hidden)]
Just(T),
#[doc(hidden)]
Nothing,
}
map_to_option!(Maybe);
impl<T: Encodable + Decodable> Encodable for Maybe<T> {
fn encode(&self, out: &mut dyn BufMut) {
match self {
Self::Just(value) => value.encode(out),
Self::Nothing => (),
}
}
}
impl<T: Encodable + Decodable> Decodable for Maybe<T> {
fn decode(buf: &mut &[u8]) -> RLPResult<Self> {
if buf.remaining() == 0 {
Ok(Self::Nothing)
} else {
Ok(Self::Just(T::decode(buf)?))
}
}
}
#[inline]
pub(crate) fn lstrip<S: AsRef<[u8]>>(bytes: S) -> Vec<u8> {
bytes
.as_ref()
.iter()
.skip_while(|&&x| x == 0)
.copied()
.collect()
}
#[inline]
pub(crate) fn static_left_pad<const N: usize>(data: &[u8]) -> RLPResult<[u8; N]> {
if data.len() > N {
return Err(RLPError::Overflow);
}
let mut v = [0; N];
if data.is_empty() {
return Ok(v);
}
if data[0] == 0 {
return Err(RLPError::LeadingZero);
}
unsafe { v.get_unchecked_mut(N - data.len()..) }.copy_from_slice(data);
Ok(v)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_left_pad() {
assert_eq!(
static_left_pad::<80>(&[1u8; 100]).unwrap_err(),
RLPError::Overflow
);
assert_eq!(static_left_pad::<10>(&[]).unwrap(), [0u8; 10]);
assert_eq!(
static_left_pad::<10>(&[0u8]).unwrap_err(),
RLPError::LeadingZero
);
assert_eq!(static_left_pad::<5>(&[1, 2, 3]).unwrap(), [0, 0, 1, 2, 3]);
}
#[test]
fn test_asbytes() {
rlp_encodable! {
#[derive(Eq, PartialEq, Debug)]
struct Test {
foo: Option<u8> => AsBytes<u8>,
}
}
let header = fastrlp::EMPTY_LIST_CODE + 1;
let empty = Test { foo: None };
let mut buf = vec![];
empty.encode(&mut buf);
assert_eq!(buf, [header, fastrlp::EMPTY_STRING_CODE]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), empty);
let full = Test { foo: Some(7) };
let mut buf = vec![];
full.encode(&mut buf);
assert_eq!(buf, [header, 7]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), full);
let buf = [header, fastrlp::EMPTY_LIST_CODE];
assert_eq!(
Test::decode(&mut &buf[..]).unwrap_err(),
RLPError::UnexpectedList
);
}
#[test]
fn test_asvec() {
rlp_encodable! {
#[derive(Eq, PartialEq, Debug)]
struct Test {
foo: Option<u8> => AsVec<u8>,
}
}
let header = fastrlp::EMPTY_LIST_CODE + 1;
let empty = Test { foo: None };
let mut buf = vec![];
empty.encode(&mut buf);
assert_eq!(buf, [header, fastrlp::EMPTY_LIST_CODE]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), empty);
let full = Test { foo: Some(7) };
let mut buf = vec![];
full.encode(&mut buf);
assert_eq!(buf, [header, 7]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), full);
let buf = [header, fastrlp::EMPTY_LIST_CODE + 1, 0x01];
assert_eq!(
Test::decode(&mut &buf[..]).unwrap_err(),
RLPError::UnexpectedList
);
let buf = [header, fastrlp::EMPTY_STRING_CODE + 1, 0x01];
assert_eq!(
Test::decode(&mut &buf[..]).unwrap_err(),
RLPError::NonCanonicalSingleByte
);
let buf = [fastrlp::EMPTY_STRING_CODE];
assert_eq!(u8::decode(&mut &buf[..]).unwrap(), 0);
let buf = [header, fastrlp::EMPTY_STRING_CODE];
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), Test { foo: Some(0) });
}
#[test]
fn test_vec_asvec() {
rlp_encodable! {
#[derive(Eq, PartialEq, Debug)]
struct Test {
foo: Option<Vec<u32>> => AsVec<Vec<u32>>,
}
}
let header = fastrlp::EMPTY_LIST_CODE + 1;
let empty = Test { foo: None };
let mut buf = vec![];
empty.encode(&mut buf);
assert_eq!(buf, [header, fastrlp::EMPTY_LIST_CODE]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), empty);
let blank = Test { foo: Some(vec![]) };
let mut buf = vec![];
blank.encode(&mut buf);
assert_eq!(buf, [header, fastrlp::EMPTY_LIST_CODE]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), empty);
let full = Test {
foo: Some(vec![0x01, 0x02]),
};
let mut buf = vec![];
full.encode(&mut buf);
assert_eq!(buf, [header + 2, fastrlp::EMPTY_LIST_CODE + 2, 0x01, 0x02]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), full);
let buf = [header, fastrlp::EMPTY_STRING_CODE + 1, 0x01];
assert_eq!(
Test::decode(&mut &buf[..]).unwrap_err(),
RLPError::NonCanonicalSingleByte
);
}
#[test]
fn test_maybe() {
rlp_encodable! {
#[derive(Eq, PartialEq, Debug)]
struct Test {
foo: Option<u8> => Maybe<u8>,
}
}
let empty = Test { foo: None };
let mut buf = vec![];
empty.encode(&mut buf);
assert_eq!(buf, [fastrlp::EMPTY_LIST_CODE]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), empty);
let full = Test { foo: Some(7) };
let mut buf = vec![];
full.encode(&mut buf);
assert_eq!(buf, [fastrlp::EMPTY_LIST_CODE + 1, 7]);
assert_eq!(Test::decode(&mut &buf[..]).unwrap(), full);
}
}