use crate::{bytes::Bytes, encode::BufferSizeError};
use ethprim::{Address, Digest, I256, U256};
use std::{borrow::Cow, mem};
pub trait EncodePacked {
fn packed_size(&self) -> usize;
fn encode_packed(&self, out: &mut [u8]);
}
pub fn encode_packed<T: EncodePacked>(value: &T) -> Vec<u8> {
let mut buf = vec![0u8; value.packed_size()];
encode_packed_to(&mut buf, value).unwrap();
buf
}
pub fn encode_packed_to<T>(buffer: &mut [u8], value: &T) -> Result<(), BufferSizeError>
where
T: EncodePacked,
{
if buffer.len() != value.packed_size() {
return Err(BufferSizeError);
}
value.encode_packed(buffer);
Ok(())
}
macro_rules! impl_encode_packed_for_integer {
($($t:ty,)*) => {$(
impl EncodePacked for $t {
fn packed_size(&self) -> usize {
mem::size_of::<Self>()
}
fn encode_packed(&self, out: &mut [u8]) {
out.copy_from_slice(&self.to_be_bytes())
}
}
)*};
}
impl_encode_packed_for_integer! {
i8, i16, i32, i64, i128, I256, isize,
u8, u16, u32, u64, u128, U256, usize,
}
impl EncodePacked for bool {
fn packed_size(&self) -> usize {
1
}
fn encode_packed(&self, out: &mut [u8]) {
out.copy_from_slice(&[*self as _]);
}
}
impl EncodePacked for Address {
fn packed_size(&self) -> usize {
20
}
fn encode_packed(&self, out: &mut [u8]) {
out.copy_from_slice(self.as_ref())
}
}
impl EncodePacked for Digest {
fn packed_size(&self) -> usize {
32
}
fn encode_packed(&self, out: &mut [u8]) {
out.copy_from_slice(self.as_ref())
}
}
macro_rules! impl_encode_packed_for_ref {
() => {
fn packed_size(&self) -> usize {
(**self).packed_size()
}
fn encode_packed(&self, out: &mut [u8]) {
(**self).encode_packed(out)
}
};
}
impl<T> EncodePacked for [T]
where
T: EncodePacked,
{
fn packed_size(&self) -> usize {
self.iter().map(|item| item.packed_size()).sum()
}
fn encode_packed(&self, out: &mut [u8]) {
let mut offset = 0;
for item in self {
let end = offset + item.packed_size();
item.encode_packed(&mut out[offset..end]);
offset = end;
}
}
}
impl<T, const N: usize> EncodePacked for [T; N]
where
T: EncodePacked,
{
fn packed_size(&self) -> usize {
self.as_slice().packed_size()
}
fn encode_packed(&self, out: &mut [u8]) {
self.as_slice().encode_packed(out)
}
}
impl<T, const N: usize> EncodePacked for &'_ [T; N]
where
T: EncodePacked,
{
impl_encode_packed_for_ref!();
}
impl<T> EncodePacked for &'_ [T]
where
T: EncodePacked,
{
impl_encode_packed_for_ref!();
}
impl<T> EncodePacked for Vec<T>
where
T: EncodePacked,
{
impl_encode_packed_for_ref!();
}
impl EncodePacked for str {
fn packed_size(&self) -> usize {
Bytes(self.as_bytes()).packed_size()
}
fn encode_packed(&self, out: &mut [u8]) {
Bytes(self.as_bytes()).encode_packed(out)
}
}
impl EncodePacked for &'_ str {
impl_encode_packed_for_ref!();
}
impl EncodePacked for String {
impl_encode_packed_for_ref!();
}
impl<T> EncodePacked for Cow<'_, T>
where
T: EncodePacked + ToOwned + ?Sized,
{
fn packed_size(&self) -> usize {
self.as_ref().packed_size()
}
fn encode_packed(&self, out: &mut [u8]) {
self.as_ref().encode_packed(out)
}
}
macro_rules! impl_encode_packed_for_tuple {
($($t:ident),*) => {
#[allow(non_snake_case, unused_variables)]
impl<$($t),*> EncodePacked for ($($t,)*)
where
$($t: EncodePacked,)*
{
fn packed_size(&self) -> usize {
let ($($t,)*) = self;
0 $(+ $t.packed_size())*
}
#[allow(unused_assignments)]
fn encode_packed(&self, out: &mut [u8]) {
let ($($t,)*) = self;
#[allow(unused_mut)]
let mut offset = 0;
$(
let end = offset + $t.packed_size();
$t.encode_packed(&mut out[offset..end]);
offset = end;
)*
}
}
impl<$($t),*> EncodePacked for &'_ ($($t,)*)
where
$($t: EncodePacked,)*
{
impl_encode_packed_for_ref!();
}
};
}
impl_encode_packed_for_tuple! {}
impl_encode_packed_for_tuple! { A }
impl_encode_packed_for_tuple! { A, B }
impl_encode_packed_for_tuple! { A, B, C }
impl_encode_packed_for_tuple! { A, B, C, D }
impl_encode_packed_for_tuple! { A, B, C, D, E }
impl_encode_packed_for_tuple! { A, B, C, D, E, F }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE }
impl_encode_packed_for_tuple! { A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, AA, AB, AC, AD, AE, AF }
#[cfg(test)]
mod tests {
use super::*;
use hex_literal::hex;
#[test]
fn encode_basic_types() {
assert_eq!(encode_packed(&0u8), hex!("00"));
assert_eq!(encode_packed(&255u8), hex!("ff"));
assert_eq!(encode_packed(&0x1234u16), hex!("1234"));
assert_eq!(encode_packed(&0x01020304i32), hex!("01020304"));
assert_eq!(encode_packed(&-1i32), hex!("ffffffff"));
let encoded = encode_packed(&1usize);
let usize_result = {
let mut bytes = [0_u8; std::mem::size_of::<usize>()];
*bytes.last_mut().unwrap() = 1;
bytes
};
assert!(encoded == usize_result);
assert_eq!(encode_packed(&-128i8), hex!("80"));
assert_eq!(encode_packed(&127i8), hex!("7f"));
assert_eq!(encode_packed(&[1u8, 2, 3]), hex!("010203"));
assert_eq!(encode_packed(&"hello"), hex!("68656c6c6f"));
assert_eq!(encode_packed(&(1u8, 2u8)), hex!("0102"));
assert_eq!(encode_packed(&(1u8, 2u8, 3u8)), hex!("010203"));
assert_eq!(encode_packed(&(1u8, 2u16, 3u32)), hex!("01000200000003"));
}
}