Skip to content

Commit

Permalink
Added CanonicalSerialize/Deserialize support for VecDeque and LinkedL…
Browse files Browse the repository at this point in the history
…ist (arkworks-rs#689)

Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
  • Loading branch information
rozbb and Pratyush authored Oct 11, 2023
1 parent 9f9edac commit 993a4e7
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Pending

- [\#689](https://github.com/arkworks-rs/algebra/pull/689) (`ark-serialize`) Add `CanonicalSerialize` and `CanonicalDeserialize` impls for `VecDeque` and `LinkedList`.

### Breaking changes

- [\#577](https://github.com/arkworks-rs/algebra/pull/577) (`ark-ff`, `ark-ec`) Add `AdditiveGroup`, a trait for additive groups (equipped with scalar field).
Expand Down
177 changes: 164 additions & 13 deletions serialize/src/impls.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use ark_std::{
borrow::Cow,
collections::{BTreeMap, BTreeSet},
borrow::{Borrow, Cow},
collections::{BTreeMap, BTreeSet, LinkedList, VecDeque},
io::{Read, Write},
marker::PhantomData,
rc::Rc,
Expand Down Expand Up @@ -529,27 +529,178 @@ impl<T: CanonicalDeserialize> CanonicalDeserialize for Vec<T> {
}
}

impl<T: CanonicalSerialize> CanonicalSerialize for [T] {
// Helper function. Serializes any sequential data type to the format
// n as u64 || data[0].serialize() || ... || data[n].serialize()
#[inline]
fn serialize_seq<T, B, W>(
seq: impl ExactSizeIterator<Item = B>,
mut writer: W,
compress: Compress,
) -> Result<(), SerializationError>
where
T: CanonicalSerialize,
B: Borrow<T>,
W: Write,
{
let len = seq.len() as u64;
len.serialize_with_mode(&mut writer, compress)?;
for item in seq {
item.borrow().serialize_with_mode(&mut writer, compress)?;
}
Ok(())
}

// Helper function. Describes the size of any data serialized using the above function
#[inline]
fn get_serialized_size_of_seq<T, B>(
seq: impl ExactSizeIterator<Item = B>,
compress: Compress,
) -> usize
where
T: CanonicalSerialize,
B: Borrow<T>,
{
8 + seq
.map(|item| item.borrow().serialized_size(compress))
.sum::<usize>()
}

impl<T: CanonicalSerialize> CanonicalSerialize for VecDeque<T> {
#[inline]
fn serialize_with_mode<W: Write>(
&self,
mut writer: W,
writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
let len = self.len() as u64;
len.serialize_with_mode(&mut writer, compress)?;
for item in self.iter() {
item.serialize_with_mode(&mut writer, compress)?;
serialize_seq::<T, _, _>(self.iter(), writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
get_serialized_size_of_seq::<T, _>(self.iter(), compress)
}
}

// Identical to Valid for Vec<T>
impl<T: Valid> Valid for VecDeque<T> {
#[inline]
fn check(&self) -> Result<(), SerializationError> {
T::batch_check(self.iter())
}

#[inline]
fn batch_check<'a>(
batch: impl Iterator<Item = &'a Self> + Send,
) -> Result<(), SerializationError>
where
Self: 'a,
{
T::batch_check(batch.flat_map(|v| v.iter()))
}
}

// Identical to CanonicalSerialize for Vec<T>, except using the push_back() method
impl<T: CanonicalDeserialize> CanonicalDeserialize for VecDeque<T> {
#[inline]
fn deserialize_with_mode<R: Read>(
mut reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let len = u64::deserialize_with_mode(&mut reader, compress, validate)?
.try_into()
.map_err(|_| SerializationError::NotEnoughSpace)?;
let mut values = VecDeque::with_capacity(len);
for _ in 0..len {
values.push_back(T::deserialize_with_mode(
&mut reader,
compress,
Validate::No,
)?);
}
Ok(())

if let Validate::Yes = validate {
T::batch_check(values.iter())?
}
Ok(values)
}
}

impl<T: CanonicalSerialize> CanonicalSerialize for LinkedList<T> {
#[inline]
fn serialize_with_mode<W: Write>(
&self,
writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
serialize_seq::<T, _, _>(self.iter(), writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
8 + self
.iter()
.map(|item| item.serialized_size(compress))
.sum::<usize>()
get_serialized_size_of_seq::<T, _>(self.iter(), compress)
}
}

// Identical to Valid for Vec<T>
impl<T: Valid> Valid for LinkedList<T> {
#[inline]
fn check(&self) -> Result<(), SerializationError> {
T::batch_check(self.iter())
}

#[inline]
fn batch_check<'a>(
batch: impl Iterator<Item = &'a Self> + Send,
) -> Result<(), SerializationError>
where
Self: 'a,
{
T::batch_check(batch.flat_map(|v| v.iter()))
}
}

// Identical to CanonicalSerialize for Vec<T>, except using the push_back() method, and the new()
// constructor.
impl<T: CanonicalDeserialize> CanonicalDeserialize for LinkedList<T> {
#[inline]
fn deserialize_with_mode<R: Read>(
mut reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let len = u64::deserialize_with_mode(&mut reader, compress, validate)?
.try_into()
.map_err(|_| SerializationError::NotEnoughSpace)?;
let mut values = LinkedList::new();
for _ in 0..len {
values.push_back(T::deserialize_with_mode(
&mut reader,
compress,
Validate::No,
)?);
}

if let Validate::Yes = validate {
T::batch_check(values.iter())?
}
Ok(values)
}
}

impl<T: CanonicalSerialize> CanonicalSerialize for [T] {
#[inline]
fn serialize_with_mode<W: Write>(
&self,
writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
serialize_seq::<T, _, _>(self.iter(), writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
get_serialized_size_of_seq::<T, _>(self.iter(), compress)
}
}

Expand Down
14 changes: 13 additions & 1 deletion serialize/src/test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::*;
use ark_std::{
collections::{BTreeMap, BTreeSet},
collections::{BTreeMap, BTreeSet, LinkedList, VecDeque},
rand::RngCore,
string::String,
vec,
Expand Down Expand Up @@ -132,6 +132,18 @@ fn test_vec() {
test_serialize(Vec::<u64>::new());
}

#[test]
fn test_vecdeque() {
test_serialize([1u64, 2, 3, 4, 5].into_iter().collect::<VecDeque<_>>());
test_serialize(VecDeque::<u64>::new());
}

#[test]
fn test_linkedlist() {
test_serialize([1u64, 2, 3, 4, 5].into_iter().collect::<LinkedList<_>>());
test_serialize(LinkedList::<u64>::new());
}

#[test]
fn test_uint() {
test_serialize(192830918usize);
Expand Down

0 comments on commit 993a4e7

Please sign in to comment.