diff --git a/Cargo.toml b/Cargo.toml index 4678dab..090810a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,9 +16,12 @@ 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 } # Implements the trait `Array` for `GenericArray` struct. generic-array = { version = "1.1.1", optional = true, default-features = false } + [features] default = [] @@ -74,11 +77,11 @@ experimental_write_impl = [] real_blackbox = ["criterion/real_blackbox"] [package.metadata.docs.rs] -features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde"] -rustdoc-args = ["--cfg", "docs_rs"] +features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh"] +rustdoc-args = ["--cfg","docs_rs"] [package.metadata.playground] -features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde"] +features = ["alloc", "std", "grab_spare_slice", "latest_stable_rust", "serde", "borsh"] [profile.bench] debug = 2 diff --git a/src/arrayvec.rs b/src/arrayvec.rs index 070bca9..884d930 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -219,6 +219,53 @@ where } } +#[cfg(feature = "borsh")] +#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))] +impl borsh::BorshSerialize for ArrayVec +where + ::Item: borsh::BorshSerialize, +{ + fn serialize( + &self, writer: &mut W, + ) -> borsh::io::Result<()> { + ::serialize(&self.len(), writer)?; + for elem in self.iter() { + <::Item as borsh::BorshSerialize>::serialize(elem, writer)?; + } + Ok(()) + } +} + +#[cfg(feature = "borsh")] +#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))] +impl borsh::BorshDeserialize for ArrayVec +where + ::Item: borsh::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> borsh::io::Result { + let len = ::deserialize_reader(reader)?; + let mut new_arrayvec = Self::default(); + + for idx in 0..len { + let value = + <::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 diff --git a/src/lib.rs b/src/lib.rs index 8ecd771..375dcc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -49,6 +49,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 diff --git a/src/tinyvec.rs b/src/tinyvec.rs index f5c236c..9afdad5 100644 --- a/src/tinyvec.rs +++ b/src/tinyvec.rs @@ -221,6 +221,47 @@ where } } +#[cfg(feature = "borsh")] +#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))] +impl borsh::BorshSerialize for TinyVec +where + ::Item: borsh::BorshSerialize, +{ + fn serialize( + &self, writer: &mut W, + ) -> borsh::io::Result<()> { + ::serialize(&self.len(), writer)?; + for elem in self.iter() { + <::Item as borsh::BorshSerialize>::serialize(elem, writer)?; + } + Ok(()) + } +} + +#[cfg(feature = "borsh")] +#[cfg_attr(docs_rs, doc(cfg(feature = "borsh")))] +impl borsh::BorshDeserialize for TinyVec +where + ::Item: borsh::BorshDeserialize, +{ + fn deserialize_reader( + reader: &mut R, + ) -> borsh::io::Result { + let len = ::deserialize_reader(reader)?; + let mut new_tinyvec = Self::with_capacity(len); + + for _ in 0..len { + new_tinyvec.push( + <::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 diff --git a/tests/arrayvec.rs b/tests/arrayvec.rs index 518b6e0..fa08273 100644 --- a/tests/arrayvec.rs +++ b/tests/arrayvec.rs @@ -447,6 +447,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; diff --git a/tests/tinyvec.rs b/tests/tinyvec.rs index 32e2a01..fca7845 100644 --- a/tests/tinyvec.rs +++ b/tests/tinyvec.rs @@ -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];