Skip to content

Commit

Permalink
Add optional support for borsh serialisation
Browse files Browse the repository at this point in the history
  • Loading branch information
Fuuzetsu committed Dec 4, 2023
1 parent d1a4700 commit 10f5a56
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 1 deletion.
4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ tinyvec_macros = { version = "0.1", optional = true }
serde = { version = "1.0", optional = true, default-features = false }
# Provides derived `Arbitrary` implementations
arbitrary = { version = "1", optional = true }
# Provides `BorshSerialize` and `BorshDeserialize implementations
borsh = { version = "1.2.0", optional = true, default-features = false }

[features]
default = []
Expand Down Expand Up @@ -63,7 +65,7 @@ experimental_write_impl = []
real_blackbox = ["criterion/real_blackbox"]

[package.metadata.docs.rs]
features = ["alloc", "std", "grab_spare_slice", "rustc_1_55", "serde"]
features = ["alloc", "std", "grab_spare_slice", "rustc_1_55", "serde", "borsh"]
rustdoc-args = ["--cfg","docs_rs"]

[package.metadata.playground]
Expand Down
47 changes: 47 additions & 0 deletions src/arrayvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,53 @@ where
}
}

#[cfg(feature = "borsh")]
#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))]
impl<A: Array> borsh::BorshSerialize for ArrayVec<A>
where
<A as Array>::Item: borsh::BorshSerialize,
{
fn serialize<W: borsh::io::Write>(
&self, writer: &mut W,
) -> borsh::io::Result<()> {
<usize as borsh::BorshSerialize>::serialize(&self.len(), writer)?;
for elem in self.iter() {
<<A as Array>::Item as borsh::BorshSerialize>::serialize(elem, writer)?;
}
Ok(())
}
}

#[cfg(feature = "borsh")]
#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))]
impl<A: Array> borsh::BorshDeserialize for ArrayVec<A>
where
<A as Array>::Item: borsh::BorshDeserialize,
{
fn deserialize_reader<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<Self> {
let len = <usize as borsh::BorshDeserialize>::deserialize_reader(reader)?;
let mut new_arrayvec = Self::default();

for idx in 0..len {
let value =
<<A as Array>::Item as borsh::BorshDeserialize>::deserialize_reader(
reader,
)?;
if idx >= new_arrayvec.capacity() {
return Err(borsh::io::Error::new(
borsh::io::ErrorKind::InvalidData,
"invalid ArrayVec length",
));
}
new_arrayvec.push(value)
}

Ok(new_arrayvec)
}
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docs_rs, doc(cfg(feature = "arbitrary")))]
impl<'a, A> arbitrary::Arbitrary<'a> for ArrayVec<A>
Expand Down
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
//! * `serde` provides a `Serialize` and `Deserialize` implementation for
//! [`TinyVec`] and [`ArrayVec`] types, provided the inner item also has an
//! implementation.
//! * `borsh` provides a `BorshSerialize` and `BorshDeserialize` implementation
//! for [`TinyVec`] and [`ArrayVec`] types, provided the inner item also has
//! an implementation.
//!
//! ## API
//! The general goal of the crate is that, as much as possible, the vecs here
Expand Down
41 changes: 41 additions & 0 deletions src/tinyvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,47 @@ where
}
}

#[cfg(feature = "borsh")]
#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))]
impl<A: Array> borsh::BorshSerialize for TinyVec<A>
where
<A as Array>::Item: borsh::BorshSerialize,
{
fn serialize<W: borsh::io::Write>(
&self, writer: &mut W,
) -> borsh::io::Result<()> {
<usize as borsh::BorshSerialize>::serialize(&self.len(), writer)?;
for elem in self.iter() {
<<A as Array>::Item as borsh::BorshSerialize>::serialize(elem, writer)?;
}
Ok(())
}
}

#[cfg(feature = "borsh")]
#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))]
impl<A: Array> borsh::BorshDeserialize for TinyVec<A>
where
<A as Array>::Item: borsh::BorshDeserialize,
{
fn deserialize_reader<R: borsh::io::Read>(
reader: &mut R,
) -> borsh::io::Result<Self> {
let len = <usize as borsh::BorshDeserialize>::deserialize_reader(reader)?;
let mut new_tinyvec = Self::with_capacity(len);

for _ in 0..len {
new_tinyvec.push(
<<A as Array>::Item as borsh::BorshDeserialize>::deserialize_reader(
reader,
)?,
)
}

Ok(new_tinyvec)
}
}

#[cfg(feature = "arbitrary")]
#[cfg_attr(docs_rs, doc(cfg(feature = "arbitrary")))]
impl<'a, A> arbitrary::Arbitrary<'a> for TinyVec<A>
Expand Down
22 changes: 22 additions & 0 deletions tests/arrayvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,28 @@ fn ArrayVec_ser_de() {
);
}

#[cfg(feature = "borsh")]
#[test]
fn ArrayVec_borsh_de_empty() {
let tv: ArrayVec<[i32; 0]> = Default::default();
let buffer = borsh::to_vec(&tv).unwrap();
let des: ArrayVec<[i32; 0]> = borsh::from_slice(&buffer).unwrap();
assert_eq!(tv, des);
}

#[cfg(feature = "borsh")]
#[test]
fn ArrayVec_borsh_de() {
let mut tv: ArrayVec<[i32; 4]> = Default::default();
tv.push(1);
tv.push(2);
tv.push(3);
tv.push(4);
let buffer = borsh::to_vec(&tv).unwrap();
let des: ArrayVec<[i32; 4]> = borsh::from_slice(&buffer).unwrap();
assert_eq!(tv, des);
}

#[test]
fn ArrayVec_try_from_slice() {
use std::convert::TryFrom;
Expand Down
33 changes: 33 additions & 0 deletions tests/tinyvec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,39 @@ fn TinyVec_ser_de_heap() {
);
}

#[cfg(feature = "borsh")]
#[test]
fn TinyVec_borsh_de_empty() {
let tv: ArrayVec<[i32; 0]> = Default::default();
let buffer = borsh::to_vec(&tv).unwrap();
let des: ArrayVec<[i32; 0]> = borsh::from_slice(&buffer).unwrap();
assert_eq!(tv, des);
}

#[cfg(feature = "borsh")]
#[test]
fn TinyVec_borsh_de() {
let mut tv: ArrayVec<[i32; 4]> = Default::default();
tv.push(1);
tv.push(2);
tv.push(3);
tv.push(4);
let buffer = borsh::to_vec(&tv).unwrap();
let des: ArrayVec<[i32; 4]> = borsh::from_slice(&buffer).unwrap();
assert_eq!(tv, des);
}

#[cfg(feature = "borsh")]
#[test]
fn TinyVec_borsh_de_heap() {
let mut tv: TinyVec<[i32; 4]> = tiny_vec![1, 2, 3, 4];
tv.move_to_the_heap();

let buffer = borsh::to_vec(&tv).unwrap();
let des: TinyVec<[i32; 4]> = borsh::from_slice(&buffer).unwrap();
assert_eq!(tv, des);
}

#[test]
fn TinyVec_pretty_debug() {
let tv: TinyVec<[i32; 6]> = tiny_vec![1, 2, 3];
Expand Down

0 comments on commit 10f5a56

Please sign in to comment.