Skip to content

Commit

Permalink
Merge pull request #98 from ralexstokes/simply-arrays
Browse files Browse the repository at this point in the history
use const generic impl for array over hard-coded values
  • Loading branch information
ralexstokes authored Jul 28, 2023
2 parents 6a21d00 + aa625fc commit 717d2e9
Showing 1 changed file with 87 additions and 110 deletions.
197 changes: 87 additions & 110 deletions ssz-rs/src/array.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,3 @@
//! This module provides `SimpleSerialize` implementations for arrays of size 1..=32.
//! These sizes are hard-coded as `SimpleSerialize` requires a `Default` implementation
//! and Rust already defines `Default` for these special array sizes.
//! If/when this restriction is lifted in favor of const generics, the macro here
//! can likely be simplified to a definition over `const N: usize`.
use crate::{
de::{deserialize_homogeneous_composite, Deserialize, DeserializeError},
error::{InstanceError, TypeError},
Expand All @@ -12,121 +7,103 @@ use crate::{
Serializable, SimpleSerialize,
};

macro_rules! define_ssz_for_array_of_size {
($n: literal) => {
impl<T> Serializable for [T; $n]
where
T: Serializable,
{
fn is_variable_size() -> bool {
T::is_variable_size()
}
impl<T, const N: usize> Serializable for [T; N]
where
T: Serializable,
{
fn is_variable_size() -> bool {
T::is_variable_size()
}

fn size_hint() -> usize {
T::size_hint() * $n
}
}
fn size_hint() -> usize {
T::size_hint() * N
}
}

impl<T> Serialize for [T; $n]
where
T: Serializable,
{
fn serialize(&self, buffer: &mut Vec<u8>) -> Result<usize, SerializeError> {
if $n == 0 {
return Err(TypeError::InvalidBound($n).into())
}
let mut serializer = Serializer::default();
for element in self {
serializer.with_element(element)?;
}
serializer.serialize(buffer)
}
impl<T, const N: usize> Serialize for [T; N]
where
T: Serializable,
{
fn serialize(&self, buffer: &mut Vec<u8>) -> Result<usize, SerializeError> {
if N == 0 {
return Err(TypeError::InvalidBound(N).into())
}
let mut serializer = Serializer::default();
for element in self {
serializer.with_element(element)?;
}
serializer.serialize(buffer)
}
}

impl<T> Deserialize for [T; $n]
where
T: Serializable,
{
fn deserialize(encoding: &[u8]) -> Result<Self, DeserializeError> {
if $n == 0 {
return Err(TypeError::InvalidBound($n).into())
}
impl<T, const N: usize> Deserialize for [T; N]
where
T: Serializable,
{
fn deserialize(encoding: &[u8]) -> Result<Self, DeserializeError> {
if N == 0 {
return Err(TypeError::InvalidBound(N).into())
}

if !T::is_variable_size() {
let expected_length = $n * T::size_hint();
if encoding.len() < expected_length {
return Err(DeserializeError::ExpectedFurtherInput {
provided: encoding.len(),
expected: expected_length,
})
}
if encoding.len() > expected_length {
return Err(DeserializeError::AdditionalInput {
provided: encoding.len(),
expected: expected_length,
})
}
}
let elements = deserialize_homogeneous_composite(encoding)?;
elements.try_into().map_err(|elements: Vec<T>| {
InstanceError::Exact { required: $n, provided: elements.len() }.into()
if !T::is_variable_size() {
let expected_length = N * T::size_hint();
if encoding.len() < expected_length {
return Err(DeserializeError::ExpectedFurtherInput {
provided: encoding.len(),
expected: expected_length,
})
}
}

impl<T> Merkleized for [T; $n]
where
T: SimpleSerialize,
{
fn hash_tree_root(&mut self) -> Result<Node, MerkleizationError> {
if T::is_composite_type() {
let count = self.len();
let chunks = elements_to_chunks(self.iter_mut().enumerate(), count)?;
merkleize(&chunks, None)
} else {
let chunks = pack(self)?;
merkleize(&chunks, None)
}
if encoding.len() > expected_length {
return Err(DeserializeError::AdditionalInput {
provided: encoding.len(),
expected: expected_length,
})
}
}
let elements = deserialize_homogeneous_composite(encoding)?;
elements.try_into().map_err(|elements: Vec<T>| {
InstanceError::Exact { required: N, provided: elements.len() }.into()
})
}
}

fn is_composite_type() -> bool {
T::is_composite_type()
}
impl<T, const N: usize> Merkleized for [T; N]
where
T: SimpleSerialize,
{
fn hash_tree_root(&mut self) -> Result<Node, MerkleizationError> {
if T::is_composite_type() {
let count = self.len();
let chunks = elements_to_chunks(self.iter_mut().enumerate(), count)?;
merkleize(&chunks, None)
} else {
let chunks = pack(self)?;
merkleize(&chunks, None)
}
}

impl<T> SimpleSerialize for [T; $n] where T: SimpleSerialize {}
};
fn is_composite_type() -> bool {
T::is_composite_type()
}
}

define_ssz_for_array_of_size!(1);
define_ssz_for_array_of_size!(2);
define_ssz_for_array_of_size!(3);
define_ssz_for_array_of_size!(4);
define_ssz_for_array_of_size!(5);
define_ssz_for_array_of_size!(6);
define_ssz_for_array_of_size!(7);
define_ssz_for_array_of_size!(8);
define_ssz_for_array_of_size!(9);
define_ssz_for_array_of_size!(10);
define_ssz_for_array_of_size!(11);
define_ssz_for_array_of_size!(12);
define_ssz_for_array_of_size!(13);
define_ssz_for_array_of_size!(14);
define_ssz_for_array_of_size!(15);
define_ssz_for_array_of_size!(16);
define_ssz_for_array_of_size!(17);
define_ssz_for_array_of_size!(18);
define_ssz_for_array_of_size!(19);
define_ssz_for_array_of_size!(20);
define_ssz_for_array_of_size!(21);
define_ssz_for_array_of_size!(22);
define_ssz_for_array_of_size!(23);
define_ssz_for_array_of_size!(24);
define_ssz_for_array_of_size!(25);
define_ssz_for_array_of_size!(26);
define_ssz_for_array_of_size!(27);
define_ssz_for_array_of_size!(28);
define_ssz_for_array_of_size!(29);
define_ssz_for_array_of_size!(30);
define_ssz_for_array_of_size!(31);
define_ssz_for_array_of_size!(32);
impl<T, const N: usize> SimpleSerialize for [T; N] where T: SimpleSerialize {}

#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;

#[test]
fn test_some_arrays() {
let a = [22u8; 3];
let serialized_a = serialize(&a).unwrap();
let recovered_a = <[u8; 3]>::deserialize(&serialized_a).unwrap();
assert_eq!(a, recovered_a);

let a = [22u8; 333];
let serialized_a = serialize(&a).unwrap();
let recovered_a = <[u8; 333]>::deserialize(&serialized_a).unwrap();
assert_eq!(a, recovered_a);
}
}

0 comments on commit 717d2e9

Please sign in to comment.