Skip to content

Commit 5f04b07

Browse files
Add RuntimeVariableList and RuntimeFixedVector (#67)
* Add runtime_types * Feature gate context_deserialize impl * Fix feature deps --------- Co-authored-by: Michael Sproul <michaelsproul@users.noreply.github.com>
1 parent 695fbf0 commit 5f04b07

6 files changed

Lines changed: 500 additions & 5 deletions

File tree

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ categories = ["cryptography::cryptocurrencies"]
1313
[features]
1414
default = ["ring"]
1515
ring = ["tree_hash/ring"]
16+
runtime_types = ["dep:educe"]
1617
context_deserialize = ["dep:context_deserialize"]
1718

1819
[dependencies]
@@ -23,9 +24,12 @@ serde = "1.0.0"
2324
serde_derive = "1.0.0"
2425
typenum = "1.12.0"
2526
smallvec = "1.8.0"
26-
arbitrary = { version = "1.0", features = ["derive"], optional = true }
2727
itertools = "0.14.0"
28+
29+
# Optional dependencies
30+
arbitrary = { version = "1.0", features = ["derive"], optional = true }
2831
context_deserialize = { version = "0.2", optional = true }
32+
educe = { version = "0.6", optional = true }
2933

3034
[dev-dependencies]
3135
criterion = "0.7.0"

src/lib.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@
3737
//!
3838
//! ```
3939
40+
pub mod serde_utils;
41+
pub mod length {
42+
pub use ssz::{Fixed, Variable};
43+
}
44+
4045
#[macro_use]
4146
mod fixed_vector;
42-
pub mod serde_utils;
4347
mod tree_hash;
4448
mod variable_list;
4549

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

54-
pub mod length {
55-
pub use ssz::{Fixed, Variable};
56-
}
58+
#[cfg(feature = "runtime_types")]
59+
mod runtime_types;
60+
61+
#[cfg(feature = "runtime_types")]
62+
pub use runtime_types::{RuntimeFixedVector, RuntimeVariableList};
5763

5864
/// Returned when an item encounters an error.
5965
#[derive(PartialEq, Debug, Clone)]
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use crate::RuntimeVariableList;
2+
use context_deserialize::ContextDeserialize;
3+
use serde::{de::Error as DeError, Deserializer};
4+
5+
impl<'de, C, T> ContextDeserialize<'de, (C, usize)> for RuntimeVariableList<T>
6+
where
7+
T: ContextDeserialize<'de, C>,
8+
C: Clone,
9+
{
10+
fn context_deserialize<D>(deserializer: D, context: (C, usize)) -> Result<Self, D::Error>
11+
where
12+
D: Deserializer<'de>,
13+
{
14+
// First parse out a Vec<C> using the Vec<C> impl you already have.
15+
let vec: Vec<T> = Vec::context_deserialize(deserializer, context.0)?;
16+
let vec_len = vec.len();
17+
RuntimeVariableList::new(vec, context.1).map_err(|e| {
18+
DeError::custom(format!(
19+
"RuntimeVariableList length {} exceeds max_len {}: {e:?}",
20+
vec_len, context.1,
21+
))
22+
})
23+
}
24+
}

src/runtime_types/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#[cfg(feature = "context_deserialize")]
2+
mod context_deserialize;
3+
mod runtime_fixed_vector;
4+
mod runtime_variable_list;
5+
6+
pub use runtime_fixed_vector::RuntimeFixedVector;
7+
pub use runtime_variable_list::RuntimeVariableList;
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
//! Emulates a fixed size array but with the length set at runtime.
2+
//!
3+
//! The length of the list cannot be changed once it is set.
4+
5+
use std::fmt;
6+
use std::fmt::Debug;
7+
8+
#[derive(Clone)]
9+
pub struct RuntimeFixedVector<T> {
10+
vec: Vec<T>,
11+
len: usize,
12+
}
13+
14+
impl<T: Debug> Debug for RuntimeFixedVector<T> {
15+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
16+
write!(f, "{:?} (len={})", self.vec, self.len)
17+
}
18+
}
19+
20+
impl<T: Clone + Default> RuntimeFixedVector<T> {
21+
pub fn new(vec: Vec<T>) -> Self {
22+
let len = vec.len();
23+
Self { vec, len }
24+
}
25+
26+
pub fn to_vec(&self) -> Vec<T> {
27+
self.vec.clone()
28+
}
29+
30+
pub fn as_slice(&self) -> &[T] {
31+
self.vec.as_slice()
32+
}
33+
34+
#[allow(clippy::len_without_is_empty)]
35+
pub fn len(&self) -> usize {
36+
self.len
37+
}
38+
39+
pub fn into_vec(self) -> Vec<T> {
40+
self.vec
41+
}
42+
43+
pub fn default(max_len: usize) -> Self {
44+
Self {
45+
vec: vec![T::default(); max_len],
46+
len: max_len,
47+
}
48+
}
49+
50+
pub fn take(&mut self) -> Self {
51+
let new = std::mem::take(&mut self.vec);
52+
*self = Self::new(vec![T::default(); self.len]);
53+
Self {
54+
vec: new,
55+
len: self.len,
56+
}
57+
}
58+
}
59+
60+
impl<T> std::ops::Deref for RuntimeFixedVector<T> {
61+
type Target = [T];
62+
63+
fn deref(&self) -> &[T] {
64+
&self.vec[..]
65+
}
66+
}
67+
68+
impl<T> std::ops::DerefMut for RuntimeFixedVector<T> {
69+
fn deref_mut(&mut self) -> &mut [T] {
70+
&mut self.vec[..]
71+
}
72+
}
73+
74+
impl<T> IntoIterator for RuntimeFixedVector<T> {
75+
type Item = T;
76+
type IntoIter = std::vec::IntoIter<T>;
77+
78+
fn into_iter(self) -> Self::IntoIter {
79+
self.vec.into_iter()
80+
}
81+
}
82+
83+
impl<'a, T> IntoIterator for &'a RuntimeFixedVector<T> {
84+
type Item = &'a T;
85+
type IntoIter = std::slice::Iter<'a, T>;
86+
87+
fn into_iter(self) -> Self::IntoIter {
88+
self.vec.iter()
89+
}
90+
}

0 commit comments

Comments
 (0)