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

Implement serialization and deserialization for usize type #238

Merged
merged 1 commit into from
Dec 29, 2023
Merged
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
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## 0.7.5 (2023-12-21) - `utils/core` crate only
* Added variable-length serialization and deserialization for `usize` type (#238).

## 0.7.4 (2023-12-18) - `air` crate only
* Fixed a bug in `StarkProof` deserialization (#236).

Expand Down
3 changes: 3 additions & 0 deletions utils/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ std = []

[dependencies]
rayon = { version = "1.8", optional = true }

[dev-dependencies]
proptest = "1.3"
35 changes: 35 additions & 0 deletions utils/core/src/serde/byte_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,41 @@ pub trait ByteReader {
Ok(u64::from_le_bytes(bytes))
}

/// Returns a usize value read from `self` in [vint64](https://docs.rs/vint64/latest/vint64/)
/// format.
///
/// # Errors
/// Returns a [DeserializationError] if:
/// * usize value could not be read from `self`.
/// * encoded value is greater than `usize` maximum value on a given platform.
fn read_usize(&mut self) -> Result<usize, DeserializationError> {
let first_byte = self.peek_u8()?;
let length = first_byte.trailing_zeros() as usize + 1;

let result = if length == 9 {
// 9-byte special case
self.read_u8()?;
let value = self.read_array::<8>()?;
u64::from_le_bytes(value)
} else {
let mut encoded = [0u8; 8];
let value = self.read_slice(length)?;
encoded[..length].copy_from_slice(value);
u64::from_le_bytes(encoded) >> length
};

// check if the result value is within acceptable bounds for `usize` on a given platform
if result > usize::MAX as u64 {
return Err(DeserializationError::InvalidValue(format!(
"Encoded value must be less than {}, but {} was provided",
usize::MAX,
result
)));
}

Ok(result as usize)
}

/// Returns a u128 value read from `self` in little-endian byte order.
///
/// # Errors
Expand Down
28 changes: 28 additions & 0 deletions utils/core/src/serde/byte_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,24 @@ pub trait ByteWriter: Sized {
self.write_bytes(&value.to_le_bytes());
}

/// Writes a usize value in [vint64](https://docs.rs/vint64/latest/vint64/) format into `self`.
///
/// # Panics
/// Panics if the value could not be written into `self`.
fn write_usize(&mut self, value: usize) {
let length = encoded_len(value);

// 9-byte special case
if length == 9 {
// length byte is zero in this case
self.write_u8(0);
self.write(value.to_le_bytes());
} else {
let encoded_bytes = ((value << 1 | 1) << (length - 1)).to_le_bytes();
self.write_bytes(&encoded_bytes[..length]);
}
}

/// Writes a serializable value into `self`.
///
/// # Panics
Expand All @@ -83,3 +101,13 @@ impl ByteWriter for Vec<u8> {
self.extend_from_slice(values);
}
}

// HELPER FUNCTIONS
// ================================================================================================

/// Returns the length of the value in vint64 enсoding.
pub fn encoded_len(value: usize) -> usize {
let zeros = value.leading_zeros() as usize;
let len = zeros.saturating_sub(1) / 7;
9 - core::cmp::min(len, 8)
}
12 changes: 12 additions & 0 deletions utils/core/src/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@ impl Serializable for u64 {
}
}

impl Serializable for usize {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
target.write_usize(*self)
}
}

impl<T: Serializable> Serializable for Option<T> {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
match self {
Expand Down Expand Up @@ -387,6 +393,12 @@ impl Deserializable for u64 {
}
}

impl Deserializable for usize {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
source.read_usize()
}
}

impl<T: Deserializable> Deserializable for Option<T> {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
let contains = source.read_bool()?;
Expand Down
37 changes: 37 additions & 0 deletions utils/core/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// LICENSE file in the root directory of this source tree.

use super::{collections::Vec, ByteReader, ByteWriter, Serializable, SliceReader};
use proptest::prelude::{any, proptest};

// VECTOR UTILS TESTS
// ================================================================================================
Expand Down Expand Up @@ -112,6 +113,29 @@ fn write_serializable() {
assert_eq!(234567u128, reader.read_u128().unwrap());
}

#[test]
fn write_serializable_usize() {
irakliyk marked this conversation as resolved.
Show resolved Hide resolved
let mut target: Vec<u8> = Vec::new();

target.write(0usize);
assert_eq!(1, target.len());
target.write(1usize);
assert_eq!(2, target.len());
target.write(255usize);
assert_eq!(4, target.len());
target.write(234567usize);
assert_eq!(7, target.len());
target.write(usize::MAX);
assert_eq!(16, target.len());

let mut reader = SliceReader::new(&target);
assert_eq!(0usize, reader.read_usize().unwrap());
assert_eq!(1usize, reader.read_usize().unwrap());
assert_eq!(255usize, reader.read_usize().unwrap());
assert_eq!(234567usize, reader.read_usize().unwrap());
assert_eq!(usize::MAX, reader.read_usize().unwrap());
}

#[test]
fn write_serializable_batch() {
let mut target: Vec<u8> = Vec::new();
Expand Down Expand Up @@ -147,3 +171,16 @@ fn write_serializable_array_batch() {
assert_eq!(i, reader.read_u128().unwrap());
}
}

// UTILS - RANDOMIZED - UINT SERIALIZATION AND DESERIALIZATION
// ================================================================================================
proptest! {
#[test]
fn usize_proptest(a in any::<usize>()) {
let mut target: Vec<u8> = Vec::new();
target.write(a);

let mut reader = SliceReader::new(&target);
assert_eq!(a, reader.read_usize().unwrap());
}
}
Loading