Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ categories = ["cryptography::cryptocurrencies"]
[features]
default = ["ring"]
ring = ["tree_hash/ring"]
runtime_types = ["dep:educe"]
context_deserialize = ["dep:context_deserialize"]

[dependencies]
Expand All @@ -23,9 +24,12 @@ serde = "1.0.0"
serde_derive = "1.0.0"
typenum = "1.12.0"
smallvec = "1.8.0"
arbitrary = { version = "1.0", features = ["derive"], optional = true }
itertools = "0.14.0"

# Optional dependencies
arbitrary = { version = "1.0", features = ["derive"], optional = true }
context_deserialize = { version = "0.2", optional = true }
educe = { version = "0.6", optional = true }

[dev-dependencies]
criterion = "0.7.0"
Expand Down
14 changes: 10 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@
//!
//! ```

pub mod serde_utils;
pub mod length {
pub use ssz::{Fixed, Variable};
}

#[macro_use]
mod fixed_vector;
pub mod serde_utils;
mod tree_hash;
mod variable_list;

Expand All @@ -51,9 +55,11 @@ pub use ssz::{BitList, BitVector, Bitfield};
pub use typenum;
pub use variable_list::VariableList;

pub mod length {
pub use ssz::{Fixed, Variable};
}
#[cfg(feature = "runtime_types")]
mod runtime_types;

#[cfg(feature = "runtime_types")]
pub use runtime_types::{RuntimeFixedVector, RuntimeVariableList};

/// Returned when an item encounters an error.
#[derive(PartialEq, Debug, Clone)]
Expand Down
24 changes: 24 additions & 0 deletions src/runtime_types/context_deserialize.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use crate::RuntimeVariableList;
use context_deserialize::ContextDeserialize;
use serde::{de::Error as DeError, Deserializer};

impl<'de, C, T> ContextDeserialize<'de, (C, usize)> for RuntimeVariableList<T>
where
T: ContextDeserialize<'de, C>,
C: Clone,
{
fn context_deserialize<D>(deserializer: D, context: (C, usize)) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// First parse out a Vec<C> using the Vec<C> impl you already have.
Copy link

Copilot AI Nov 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment incorrectly states 'Vec' but the actual type is 'Vec'. Update comment to say 'Vec' for accuracy.

Suggested change
// First parse out a Vec<C> using the Vec<C> impl you already have.
// First parse out a Vec<T> using the Vec<T> impl you already have.

Copilot uses AI. Check for mistakes.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird way to phrase this, but it's right

let vec: Vec<T> = Vec::context_deserialize(deserializer, context.0)?;
let vec_len = vec.len();
RuntimeVariableList::new(vec, context.1).map_err(|e| {
DeError::custom(format!(
"RuntimeVariableList length {} exceeds max_len {}: {e:?}",
vec_len, context.1,
))
})
}
}
7 changes: 7 additions & 0 deletions src/runtime_types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#[cfg(feature = "context_deserialize")]
mod context_deserialize;
mod runtime_fixed_vector;
mod runtime_variable_list;

pub use runtime_fixed_vector::RuntimeFixedVector;
pub use runtime_variable_list::RuntimeVariableList;
90 changes: 90 additions & 0 deletions src/runtime_types/runtime_fixed_vector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! Emulates a fixed size array but with the length set at runtime.
//!
//! The length of the list cannot be changed once it is set.

use std::fmt;
use std::fmt::Debug;

#[derive(Clone)]
pub struct RuntimeFixedVector<T> {
vec: Vec<T>,
len: usize,
}

impl<T: Debug> Debug for RuntimeFixedVector<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?} (len={})", self.vec, self.len)
}
}

impl<T: Clone + Default> RuntimeFixedVector<T> {
pub fn new(vec: Vec<T>) -> Self {
let len = vec.len();
Self { vec, len }
}

pub fn to_vec(&self) -> Vec<T> {
self.vec.clone()
}

pub fn as_slice(&self) -> &[T] {
self.vec.as_slice()
}

#[allow(clippy::len_without_is_empty)]
pub fn len(&self) -> usize {
self.len
}

pub fn into_vec(self) -> Vec<T> {
self.vec
}

pub fn default(max_len: usize) -> Self {
Self {
vec: vec![T::default(); max_len],
len: max_len,
}
}

pub fn take(&mut self) -> Self {
let new = std::mem::take(&mut self.vec);
*self = Self::new(vec![T::default(); self.len]);
Self {
vec: new,
len: self.len,
}
}
}

impl<T> std::ops::Deref for RuntimeFixedVector<T> {
type Target = [T];

fn deref(&self) -> &[T] {
&self.vec[..]
}
}

impl<T> std::ops::DerefMut for RuntimeFixedVector<T> {
fn deref_mut(&mut self) -> &mut [T] {
&mut self.vec[..]
}
}

impl<T> IntoIterator for RuntimeFixedVector<T> {
type Item = T;
type IntoIter = std::vec::IntoIter<T>;

fn into_iter(self) -> Self::IntoIter {
self.vec.into_iter()
}
}

impl<'a, T> IntoIterator for &'a RuntimeFixedVector<T> {
type Item = &'a T;
type IntoIter = std::slice::Iter<'a, T>;

fn into_iter(self) -> Self::IntoIter {
self.vec.iter()
}
}
Loading
Loading