Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compute packed leaf values on demand (Option 1) #19

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
7 changes: 3 additions & 4 deletions src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::utils::{opt_packing_depth, opt_packing_factor, Length};
use crate::{Arc, Error, PackedLeaf, Tree};
use tree_hash::TreeHash;
use crate::{Arc, Error, PackedLeaf, Tree, Value};

pub struct Builder<T: TreeHash + Clone> {
pub struct Builder<T: Value> {
stack: Vec<Tree<T>>,
depth: usize,
length: Length,
Expand All @@ -12,7 +11,7 @@ pub struct Builder<T: TreeHash + Clone> {
packing_depth: usize,
}

impl<T: TreeHash + Clone> Builder<T> {
impl<T: Value> Builder<T> {
pub fn new(depth: usize) -> Self {
Self {
stack: Vec::with_capacity(depth),
Expand Down
20 changes: 7 additions & 13 deletions src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ use crate::utils::{updated_length, Length};
use crate::{
interface_iter::{InterfaceIter, InterfaceIterCow},
iter::Iter,
Cow, Error,
Cow, Error, Value,
};
use arbitrary::Arbitrary;
use std::collections::BTreeMap;
use std::marker::PhantomData;
use tree_hash::{Hash256, TreeHash};
use tree_hash::Hash256;

pub trait ImmList<T>
where
T: TreeHash + Clone,
{
pub trait ImmList<T: Value> {
fn get(&self, idx: usize) -> Option<&T>;

fn len(&self) -> Length;
Expand All @@ -25,10 +22,7 @@ where
fn iter_from(&self, index: usize) -> Iter<T>;
}

pub trait MutList<T>: ImmList<T>
where
T: TreeHash + Clone,
{
pub trait MutList<T: Value>: ImmList<T> {
fn validate_push(current_len: usize) -> Result<(), Error>;
fn replace(&mut self, index: usize, value: T) -> Result<(), Error>;
fn update<U: UpdateMap<T>>(
Expand All @@ -41,7 +35,7 @@ where
#[derive(Debug, PartialEq, Clone, Arbitrary)]
pub struct Interface<T, B, U>
where
T: TreeHash + Clone,
T: Value,
B: MutList<T>,
U: UpdateMap<T>,
{
Expand All @@ -52,7 +46,7 @@ where

impl<T, B, U> Interface<T, B, U>
where
T: TreeHash + Clone,
T: Value,
B: MutList<T>,
U: UpdateMap<T>,
{
Expand Down Expand Up @@ -180,7 +174,7 @@ mod test {
*c2.to_mut() = 11;
assert_eq!(*list.get(0).unwrap(), 11);

assert_eq!(list.iter().cloned().collect::<Vec<_>>(), vec![11, 2, 3]);
assert_eq!(list.iter().copied().collect::<Vec<_>>(), vec![11, 2, 3]);
}

#[test]
Expand Down
13 changes: 6 additions & 7 deletions src/interface_iter.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
use crate::iter::Iter;
use crate::{Cow, UpdateMap};
use tree_hash::TreeHash;
use crate::{Cow, UpdateMap, Value};

#[derive(Debug)]
pub struct InterfaceIter<'a, T: TreeHash + Clone, U: UpdateMap<T>> {
pub struct InterfaceIter<'a, T: Value, U: UpdateMap<T>> {
pub(crate) tree_iter: Iter<'a, T>,
pub(crate) updates: &'a U,
pub(crate) index: usize,
pub(crate) length: usize,
}

impl<'a, T: TreeHash + Clone, U: UpdateMap<T>> Iterator for InterfaceIter<'a, T, U> {
impl<'a, T: Value, U: UpdateMap<T>> Iterator for InterfaceIter<'a, T, U> {
type Item = &'a T;

fn next(&mut self) -> Option<&'a T> {
Expand All @@ -30,16 +29,16 @@ impl<'a, T: TreeHash + Clone, U: UpdateMap<T>> Iterator for InterfaceIter<'a, T,
}
}

impl<'a, T: TreeHash + Clone, U: UpdateMap<T>> ExactSizeIterator for InterfaceIter<'a, T, U> {}
impl<'a, T: Value, U: UpdateMap<T>> ExactSizeIterator for InterfaceIter<'a, T, U> {}

#[derive(Debug)]
pub struct InterfaceIterCow<'a, T: TreeHash + Clone, U: UpdateMap<T>> {
pub struct InterfaceIterCow<'a, T: Value, U: UpdateMap<T>> {
pub(crate) tree_iter: Iter<'a, T>,
pub(crate) updates: &'a mut U,
pub(crate) index: usize,
}

impl<'a, T: TreeHash + Clone, U: UpdateMap<T>> InterfaceIterCow<'a, T, U> {
impl<'a, T: Value, U: UpdateMap<T>> InterfaceIterCow<'a, T, U> {
pub fn next_cow(&mut self) -> Option<(usize, Cow<T>)> {
let index = self.index;
self.index += 1;
Expand Down
15 changes: 7 additions & 8 deletions src/iter.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::{
utils::{opt_packing_depth, opt_packing_factor, Length},
Leaf, PackedLeaf, Tree,
Leaf, Tree, Value,
};
use tree_hash::TreeHash;

#[derive(Debug)]
pub struct Iter<'a, T: TreeHash + Clone> {
pub struct Iter<'a, T: Value> {
/// Stack of tree nodes corresponding to the current position.
stack: Vec<&'a Tree<T>>,
/// The list index corresponding to the current position (next element to be yielded).
Expand All @@ -22,7 +21,7 @@ pub struct Iter<'a, T: TreeHash + Clone> {
length: Length,
}

impl<'a, T: TreeHash + Clone> Iter<'a, T> {
impl<'a, T: Value> Iter<'a, T> {
pub fn from_index(index: usize, root: &'a Tree<T>, depth: usize, length: Length) -> Self {
let mut stack = Vec::with_capacity(depth);
stack.push(root);
Expand All @@ -38,7 +37,7 @@ impl<'a, T: TreeHash + Clone> Iter<'a, T> {
}
}

impl<'a, T: TreeHash + Clone> Iterator for Iter<'a, T> {
impl<'a, T: Value> Iterator for Iter<'a, T> {
type Item = &'a T;

fn next(&mut self) -> Option<Self::Item> {
Expand All @@ -60,10 +59,10 @@ impl<'a, T: TreeHash + Clone> Iterator for Iter<'a, T> {

result
}
Some(Tree::PackedLeaf(PackedLeaf { values, .. })) => {
Some(Tree::PackedLeaf(packed_leaf)) => {
let sub_index = self.index % self.packing_factor;

let result = values.get(sub_index);
let result = packed_leaf.get(sub_index);

self.index += 1;

Expand Down Expand Up @@ -105,4 +104,4 @@ impl<'a, T: TreeHash + Clone> Iterator for Iter<'a, T> {
}
}

impl<'a, T: TreeHash + Clone> ExactSizeIterator for Iter<'a, T> {}
impl<'a, T: Value> ExactSizeIterator for Iter<'a, T> {}
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,10 @@ pub use tree::Tree;
pub use triomphe::Arc;
pub use update_map::UpdateMap;
pub use vector::Vector;

use ssz::{Decode, Encode};
use tree_hash::TreeHash;

pub trait Value: Encode + Decode + TreeHash + PartialEq + Clone {}

impl<T> Value for T where T: Encode + Decode + TreeHash + PartialEq + Clone {}
56 changes: 27 additions & 29 deletions src/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::iter::Iter;
use crate::serde::ListVisitor;
use crate::update_map::MaxMap;
use crate::utils::{arb_arc, int_log, opt_packing_depth, updated_length, Length};
use crate::{Arc, Cow, Error, Tree, UpdateMap};
use crate::{Arc, Cow, Error, Tree, UpdateMap, Value};
use arbitrary::Arbitrary;
use derivative::Derivative;
use itertools::process_results;
Expand All @@ -19,19 +19,17 @@ use typenum::Unsigned;
use vec_map::VecMap;

#[derive(Debug, Clone, Derivative, Arbitrary)]
#[derivative(PartialEq(
bound = "T: TreeHash + PartialEq + Clone, N: Unsigned, U: UpdateMap<T> + PartialEq"
))]
#[arbitrary(bound = "T: Arbitrary<'arbitrary> + TreeHash + PartialEq + Clone")]
#[derivative(PartialEq(bound = "T: Value, N: Unsigned, U: UpdateMap<T> + PartialEq"))]
#[arbitrary(bound = "T: Arbitrary<'arbitrary> + Value")]
#[arbitrary(bound = "N: Unsigned, U: Arbitrary<'arbitrary> + UpdateMap<T> + PartialEq")]
pub struct List<T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T> = MaxMap<VecMap<T>>> {
pub struct List<T: Value, N: Unsigned, U: UpdateMap<T> = MaxMap<VecMap<T>>> {
pub(crate) interface: Interface<T, ListInner<T, N>, U>,
}

#[derive(Debug, Clone, Derivative, Arbitrary)]
#[derivative(PartialEq(bound = "T: TreeHash + PartialEq + Clone, N: Unsigned"))]
#[arbitrary(bound = "T: Arbitrary<'arbitrary> + TreeHash + PartialEq + Clone, N: Unsigned")]
pub struct ListInner<T: TreeHash + Clone, N: Unsigned> {
#[derivative(PartialEq(bound = "T: Value, N: Unsigned"))]
#[arbitrary(bound = "T: Arbitrary<'arbitrary> + Value, N: Unsigned")]
pub struct ListInner<T: Value, N: Unsigned> {
#[arbitrary(with = arb_arc)]
pub(crate) tree: Arc<Tree<T>>,
pub(crate) length: Length,
Expand All @@ -41,7 +39,7 @@ pub struct ListInner<T: TreeHash + Clone, N: Unsigned> {
_phantom: PhantomData<N>,
}

impl<T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T>> List<T, N, U> {
impl<T: Value, N: Unsigned, U: UpdateMap<T>> List<T, N, U> {
pub fn new(vec: Vec<T>) -> Result<Self, Error> {
Self::try_from_iter(vec)
}
Expand Down Expand Up @@ -173,7 +171,7 @@ impl<T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T>> List<T, N, U> {
}
}

impl<T: TreeHash + Clone, N: Unsigned> ImmList<T> for ListInner<T, N> {
impl<T: Value, N: Unsigned> ImmList<T> for ListInner<T, N> {
fn get(&self, index: usize) -> Option<&T> {
if index < self.len().as_usize() {
self.tree
Expand All @@ -194,7 +192,7 @@ impl<T: TreeHash + Clone, N: Unsigned> ImmList<T> for ListInner<T, N> {

impl<T, N> MutList<T> for ListInner<T, N>
where
T: TreeHash + Clone,
T: Value,
N: Unsigned,
{
fn validate_push(current_len: usize) -> Result<(), Error> {
Expand Down Expand Up @@ -241,9 +239,7 @@ where
}
}

impl<T: TreeHash + PartialEq + Clone + Decode + Encode, N: Unsigned, U: UpdateMap<T>>
List<T, N, U>
{
impl<T: Value, N: Unsigned, U: UpdateMap<T>> List<T, N, U> {
pub fn rebase(&self, base: &Self) -> Result<Self, Error> {
// Diff self from base.
let diff = ListDiff::compute_diff(base, self)?;
Expand All @@ -262,13 +258,13 @@ impl<T: TreeHash + PartialEq + Clone + Decode + Encode, N: Unsigned, U: UpdateMa
}
}

impl<T: TreeHash + Clone, N: Unsigned> Default for List<T, N> {
impl<T: Value, N: Unsigned> Default for List<T, N> {
fn default() -> Self {
Self::empty()
}
}

impl<T: TreeHash + Clone + Send + Sync, N: Unsigned> TreeHash for List<T, N> {
impl<T: Value + Send + Sync, N: Unsigned> TreeHash for List<T, N> {
fn tree_hash_type() -> tree_hash::TreeHashType {
tree_hash::TreeHashType::List
}
Expand All @@ -290,7 +286,7 @@ impl<T: TreeHash + Clone + Send + Sync, N: Unsigned> TreeHash for List<T, N> {
}
}

impl<'a, T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T>> IntoIterator for &'a List<T, N, U> {
impl<'a, T: Value, N: Unsigned, U: UpdateMap<T>> IntoIterator for &'a List<T, N, U> {
type Item = &'a T;
type IntoIter = InterfaceIter<'a, T, U>;

Expand All @@ -299,7 +295,7 @@ impl<'a, T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T>> IntoIterator for &'a
}
}

impl<T: TreeHash + Clone, N: Unsigned, U: UpdateMap<T>> Serialize for List<T, N, U>
impl<T: Value, N: Unsigned, U: UpdateMap<T>> Serialize for List<T, N, U>
where
T: Serialize,
{
Expand All @@ -309,15 +305,15 @@ where
{
let mut seq = serializer.serialize_seq(Some(self.len()))?;
for e in self {
seq.serialize_element(e)?;
seq.serialize_element(&e)?;
}
seq.end()
}
}

impl<'de, T, N, U> Deserialize<'de> for List<T, N, U>
where
T: Deserialize<'de> + TreeHash + Clone,
T: Deserialize<'de> + Value,
N: Unsigned,
U: UpdateMap<T>,
{
Expand All @@ -330,7 +326,7 @@ where
}

// FIXME: duplicated from `ssz::encode::impl_for_vec`
impl<T: Encode + TreeHash + Clone, N: Unsigned> Encode for List<T, N> {
impl<T: Value, N: Unsigned> Encode for List<T, N> {
fn is_ssz_fixed_len() -> bool {
false
}
Expand All @@ -346,8 +342,8 @@ impl<T: Encode + TreeHash + Clone, N: Unsigned> Encode for List<T, N> {
}

fn ssz_append(&self, buf: &mut Vec<u8>) {
if T::is_ssz_fixed_len() {
buf.reserve(T::ssz_fixed_len() * self.len());
if <T as Encode>::is_ssz_fixed_len() {
buf.reserve(<T as Encode>::ssz_fixed_len() * self.len());

for item in self {
item.ssz_append(buf);
Expand All @@ -366,7 +362,7 @@ impl<T: Encode + TreeHash + Clone, N: Unsigned> Encode for List<T, N> {

impl<T, N> TryFromIter<T> for List<T, N>
where
T: TreeHash + Clone,
T: Value,
N: Unsigned,
{
type Error = Error;
Expand All @@ -381,7 +377,7 @@ where

impl<T, N> Decode for List<T, N>
where
T: Decode + TreeHash + Clone,
T: Value,
N: Unsigned,
{
fn is_ssz_fixed_len() -> bool {
Expand All @@ -393,10 +389,10 @@ where

if bytes.is_empty() {
Ok(List::empty())
} else if T::is_ssz_fixed_len() {
} else if <T as Decode>::is_ssz_fixed_len() {
let num_items = bytes
.len()
.checked_div(T::ssz_fixed_len())
.checked_div(<T as Decode>::ssz_fixed_len())
.ok_or(ssz::DecodeError::ZeroLengthItem)?;

if num_items > max_len {
Expand All @@ -407,7 +403,9 @@ where
}

process_results(
bytes.chunks(T::ssz_fixed_len()).map(T::from_ssz_bytes),
bytes
.chunks(<T as Decode>::ssz_fixed_len())
.map(T::from_ssz_bytes),
|iter| {
List::try_from_iter(iter).map_err(|e| {
ssz::DecodeError::BytesInvalid(format!("Error building ssz List: {:?}", e))
Expand Down
Loading