Skip to content
Draft
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
14 changes: 8 additions & 6 deletions ssz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,19 @@ categories.workspace = true
name = "ssz"

[features]
default = ["std"]
std = ["alloy-primitives/std", "ethereum_serde_utils/std", "serde/std", "itertools/use_std"]
arbitrary = ["dep:arbitrary", "alloy-primitives/arbitrary"]
context_deserialize = ["dep:context_deserialize"]

[dependencies]
alloy-primitives = "1"
ethereum_serde_utils = "0.8"
smallvec = { version = "1", features = ["const_generics"] }
itertools = "0.14"
serde = "1"
alloy-primitives = { version = "1", default-features = false }
ethereum_serde_utils = { version = "0.8", default-features = false }
smallvec = { version = "1", default-features = false, features = ["const_generics"] }
itertools = { version = "0.14", default-features = false, features = ["use_alloc"] }
serde = { version = "1", default-features = false, features = ["alloc"] }
serde_derive = "1"
typenum = "1"
typenum = { version = "1", default-features = false }
arbitrary = { version = "1", features = ["derive"], optional = true }
context_deserialize = { version = "0.2", optional = true }

Expand Down
31 changes: 21 additions & 10 deletions ssz/src/bitfield.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use crate::{Decode, DecodeError, Encode};
use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::marker::PhantomData;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
Expand Down Expand Up @@ -230,7 +234,7 @@ impl<N: Unsigned + Clone> Bitfield<Variable<N>> {
///
/// Return a new BitList with length equal to the shorter of the two inputs.
pub fn intersection(&self, other: &Self) -> Self {
let min_len = std::cmp::min(self.len(), other.len());
let min_len = core::cmp::min(self.len(), other.len());
let mut result = Self::with_capacity(min_len).expect("min len always less than N");
// Bitwise-and the bytes together, starting from the left of each vector. This takes care
// of masking out any entries beyond `min_len` as well, assuming the bitfield doesn't
Expand All @@ -245,7 +249,7 @@ impl<N: Unsigned + Clone> Bitfield<Variable<N>> {
///
/// Return a new BitList with length equal to the longer of the two inputs.
pub fn union(&self, other: &Self) -> Self {
let max_len = std::cmp::max(self.len(), other.len());
let max_len = core::cmp::max(self.len(), other.len());
let mut result = Self::with_capacity(max_len).expect("max len always less than N");
for i in 0..result.bytes.len() {
result.bytes[i] =
Expand Down Expand Up @@ -350,8 +354,8 @@ impl<N: Unsigned + Clone> Bitfield<Fixed<N>> {
}
}

impl<T: BitfieldBehaviour> std::fmt::Display for Bitfield<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
impl<T: BitfieldBehaviour> core::fmt::Display for Bitfield<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut field: String = "".to_string();
for i in self.iter() {
if i {
Expand All @@ -364,6 +368,13 @@ impl<T: BitfieldBehaviour> std::fmt::Display for Bitfield<T> {
}
}

/// An empty bit list, mirroring the fixed variant's `Default`. Zero length is a valid `BitList`.
impl<N: Unsigned + Clone> Default for Bitfield<Variable<N>> {
fn default() -> Self {
Self::with_capacity(0).expect("a zero length bitlist is within any bound")
}
}

impl<N: Unsigned + Clone> Default for Bitfield<Fixed<N>> {
fn default() -> Self {
Self::new()
Expand Down Expand Up @@ -514,7 +525,7 @@ impl<T: BitfieldBehaviour> Bitfield<T> {

/// Compute the difference of this Bitfield and another of potentially different length.
pub fn difference_inplace(&mut self, other: &Self) {
let min_byte_len = std::cmp::min(self.bytes.len(), other.bytes.len());
let min_byte_len = core::cmp::min(self.bytes.len(), other.bytes.len());

for i in 0..min_byte_len {
self.bytes[i] &= !other.bytes[i];
Expand Down Expand Up @@ -599,7 +610,7 @@ impl<T> core::hash::Hash for Bitfield<T> {
///
/// `bit_len == 0` requires a single byte.
fn bytes_for_bit_len(bit_len: usize) -> usize {
std::cmp::max(1, bit_len.div_ceil(8))
core::cmp::max(1, bit_len.div_ceil(8))
}

/// Returns the number of bytes in the SSZ encoding of a variable-length bitfield (`BitList` or
Expand Down Expand Up @@ -957,7 +968,7 @@ mod bitvector {
assert_round_trip(b);
}

fn assert_round_trip<T: Encode + Decode + PartialEq + std::fmt::Debug>(t: T) {
fn assert_round_trip<T: Encode + Decode + PartialEq + core::fmt::Debug>(t: T) {
assert_eq!(T::from_ssz_bytes(&t.as_ssz_bytes()).unwrap(), t);
}

Expand All @@ -983,7 +994,7 @@ mod bitvector {
// Ensure that stack size of a BitVector is manageable.
#[test]
fn size_of() {
assert_eq!(std::mem::size_of::<BitVector64>(), SMALLVEC_LEN + 24);
assert_eq!(core::mem::size_of::<BitVector64>(), SMALLVEC_LEN + 24);
}

#[test]
Expand Down Expand Up @@ -1203,7 +1214,7 @@ mod bitlist {
}
}

fn assert_round_trip<T: Encode + Decode + PartialEq + std::fmt::Debug>(t: T) {
fn assert_round_trip<T: Encode + Decode + PartialEq + core::fmt::Debug>(t: T) {
assert_eq!(T::from_ssz_bytes(&t.as_ssz_bytes()).unwrap(), t);
}

Expand Down Expand Up @@ -1569,7 +1580,7 @@ mod bitlist {
// Ensure that the stack size of a BitList is manageable.
#[test]
fn size_of() {
assert_eq!(std::mem::size_of::<BitList1024>(), SMALLVEC_LEN + 24);
assert_eq!(core::mem::size_of::<BitList1024>(), SMALLVEC_LEN + 24);
}

#[test]
Expand Down
25 changes: 13 additions & 12 deletions ssz/src/bitfield/bitvector_dynamic.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! Provides `Bitfield<Dynamic>` (BitVectorDynamic)
/// for encoding and decoding bitvectors that have a dynamic length.
use crate::{
bitfield::{bytes_for_bit_len, Bitfield, BitfieldBehaviour, Error, SMALLVEC_LEN},
Decode, DecodeError, Encode,
};
/// for encoding and decoding bitvectors that have a dynamic length.
use alloc::vec::Vec;
use core::marker::PhantomData;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
Expand Down Expand Up @@ -63,7 +64,7 @@ impl Bitfield<Dynamic> {

/// Compute the intersection of two bitfields.
pub fn intersection(&self, other: &Self) -> Result<Self, Error> {
let max_len = std::cmp::max(self.len(), other.len());
let max_len = core::cmp::max(self.len(), other.len());
let mut result = Self::new(max_len)?;

for (i, byte) in result.bytes.iter_mut().enumerate() {
Expand All @@ -75,7 +76,7 @@ impl Bitfield<Dynamic> {

/// Compute the union of two bitfields.
pub fn union(&self, other: &Self) -> Result<Self, Error> {
let max_len = std::cmp::max(self.len(), other.len());
let max_len = core::cmp::max(self.len(), other.len());
let mut result = Self::new(max_len)?;

for (i, byte) in result.bytes.iter_mut().enumerate() {
Expand Down Expand Up @@ -150,8 +151,8 @@ mod dynamic_bitfield_tests {
assert!(bitfield.set(15, true).is_ok());
assert!(bitfield.set(16, true).is_err()); // Out of bounds

assert_eq!(bitfield.get(0)?, true);
assert_eq!(bitfield.get(15)?, true);
assert!(bitfield.get(0)?);
assert!(bitfield.get(15)?);
assert!(bitfield.get(16).is_err());

Ok(())
Expand Down Expand Up @@ -277,9 +278,9 @@ mod dynamic_bitfield_tests {
b.set(4, true)?;

let diff = a.difference(&b);
assert_eq!(diff.get(1)?, true);
assert_eq!(diff.get(3)?, false);
assert_eq!(diff.get(4)?, false);
assert!(diff.get(1)?);
assert!(!diff.get(3)?);
assert!(!diff.get(4)?);

Ok(())
}
Expand All @@ -291,9 +292,9 @@ mod dynamic_bitfield_tests {
bitfield.set(1, true)?;

bitfield.shift_up(1)?;
assert_eq!(bitfield.get(0)?, false);
assert_eq!(bitfield.get(1)?, true);
assert_eq!(bitfield.get(2)?, true);
assert!(!bitfield.get(0)?);
assert!(bitfield.get(1)?);
assert!(bitfield.get(2)?);

// Test error case
assert!(bitfield.shift_up(17).is_err());
Expand Down Expand Up @@ -480,7 +481,7 @@ mod roundtrip_tests {
use super::*;
fn assert_round_trip_bitdyn<T>(t: T) -> Result<(), Error>
where
T: Encode + Decode + PartialEq + std::fmt::Debug,
T: Encode + Decode + PartialEq + core::fmt::Debug,
{
let bytes = t.as_ssz_bytes();
let decoded = T::from_ssz_bytes(&bytes).expect("decode failed in test");
Expand Down
12 changes: 8 additions & 4 deletions ssz/src/bitfield/progressive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
},
Decode, DecodeError, Encode,
};
use alloc::vec::Vec;
use core::marker::PhantomData;
use serde::de::{Deserialize, Deserializer};
use serde::ser::{Serialize, Serializer};
Expand Down Expand Up @@ -108,7 +109,7 @@ impl Bitfield<Progressive> {
///
/// Return a new ProgressiveBitList with length equal to the shorter of the two inputs.
pub fn intersection(&self, other: &Self) -> Self {
let min_len = std::cmp::min(self.len(), other.len());
let min_len = core::cmp::min(self.len(), other.len());
let mut result = Self::with_capacity(min_len);
// Bitwise-and the bytes together, starting from the left of each vector. This takes care
// of masking out any entries beyond `min_len` as well, assuming the bitfield doesn't
Expand All @@ -123,7 +124,7 @@ impl Bitfield<Progressive> {
///
/// Return a new ProgressiveBitList with length equal to the longer of the two inputs.
pub fn union(&self, other: &Self) -> Self {
let max_len = std::cmp::max(self.len(), other.len());
let max_len = core::cmp::max(self.len(), other.len());
let mut result = Self::with_capacity(max_len);
for i in 0..result.bytes.len() {
result.bytes[i] =
Expand Down Expand Up @@ -299,7 +300,7 @@ mod progressive_bitlist {
}
}

fn assert_round_trip<T: Encode + Decode + PartialEq + std::fmt::Debug>(t: T) {
fn assert_round_trip<T: Encode + Decode + PartialEq + core::fmt::Debug>(t: T) {
assert_eq!(T::from_ssz_bytes(&t.as_ssz_bytes()).unwrap(), t);
}

Expand Down Expand Up @@ -702,7 +703,10 @@ mod progressive_bitlist {
// Ensure that the stack size of a ProgressiveBitList is manageable.
#[test]
fn size_of() {
assert_eq!(std::mem::size_of::<ProgressiveBitList>(), SMALLVEC_LEN + 24);
assert_eq!(
core::mem::size_of::<ProgressiveBitList>(),
SMALLVEC_LEN + 24
);
}

#[test]
Expand Down
5 changes: 3 additions & 2 deletions ssz/src/decode.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::*;
use alloc::string::String;
use core::cmp::Ordering;
use smallvec::{smallvec, SmallVec};
use std::cmp::Ordering;

type SmallVec8<T> = SmallVec<[T; 8]>;

Expand Down Expand Up @@ -368,7 +369,7 @@ fn decode_offset(bytes: &[u8]) -> Result<usize, DecodeError> {
if len != expected {
Err(DecodeError::InvalidLengthPrefix { len, expected })
} else {
let mut array: [u8; BYTES_PER_LENGTH_OFFSET] = std::default::Default::default();
let mut array: [u8; BYTES_PER_LENGTH_OFFSET] = core::default::Default::default();
array.clone_from_slice(bytes);

Ok(u32::from_le_bytes(array) as usize)
Expand Down
9 changes: 5 additions & 4 deletions ssz/src/decode/impls.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use super::*;
use crate::decode::try_from_iter::{TryCollect, TryFromIter};
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::sync::Arc;
use alloc::{string::ToString, vec::Vec};
use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U128, U256};
use core::iter::{self, FromIterator};
use core::num::NonZeroUsize;
use itertools::process_results;
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::{self, FromIterator};
use std::sync::Arc;

macro_rules! impl_decodable_for_uint {
($type: ident, $bit_size: expr) => {
Expand All @@ -29,7 +30,7 @@ macro_rules! impl_decodable_for_uint {
if len != expected {
Err(DecodeError::InvalidByteLength { len, expected })
} else {
let mut array: [u8; $bit_size / 8] = std::default::Default::default();
let mut array: [u8; $bit_size / 8] = core::default::Default::default();
array.clone_from_slice(bytes);

Ok(Self::from_le_bytes(array))
Expand Down
9 changes: 5 additions & 4 deletions ssz/src/decode/try_from_iter.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::vec::Vec;
use core::convert::Infallible;
use core::fmt::Debug;
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::convert::Infallible;
use std::fmt::Debug;

/// Partial variant of `std::iter::FromIterator`.
/// Partial variant of `core::iter::FromIterator`.
///
/// This trait is implemented for types which can be constructed from an iterator of decoded SSZ
/// values, but which may refuse values once a length limit is reached.
Expand Down
6 changes: 3 additions & 3 deletions ssz/src/encode/impls.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use super::*;
use alloc::collections::{BTreeMap, BTreeSet};
use alloc::sync::Arc;
use alloy_primitives::{Address, Bloom, Bytes, FixedBytes, U128, U256};
use core::num::NonZeroUsize;
use smallvec::SmallVec;
use std::collections::{BTreeMap, BTreeSet};
use std::sync::Arc;

macro_rules! impl_encodable_for_uint {
($type: ident, $bit_size: expr) => {
Expand Down Expand Up @@ -404,7 +404,7 @@ impl Encode for NonZeroUsize {
}

fn ssz_bytes_len(&self) -> usize {
std::mem::size_of::<usize>()
core::mem::size_of::<usize>()
}

fn ssz_append(&self, buf: &mut Vec<u8>) {
Expand Down
2 changes: 1 addition & 1 deletion ssz/src/legacy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ mod test {
assert_eq!(impl_vec_u16::decode::from_ssz_bytes(&bytes).unwrap(), item);
}

fn round_trip<T: Encode + Decode + std::fmt::Debug + PartialEq>(items: Vec<T>) {
fn round_trip<T: Encode + Decode + core::fmt::Debug + PartialEq>(items: Vec<T>) {
for item in items {
let encoded = &item.as_ssz_bytes();
assert_eq!(item.ssz_bytes_len(), encoded.len());
Expand Down
8 changes: 8 additions & 0 deletions ssz/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@
//!
//! See `examples/` for manual implementations of the `Encode` and `Decode` traits.

#![cfg_attr(not(feature = "std"), no_std)]

#[macro_use]
extern crate alloc;

/// Re-exported so the derives can name `Vec` without relying on the consumer having imported it.
pub use alloc::vec::Vec;

mod bitfield;
mod decode;
mod encode;
Expand Down
Loading