From 148749a653275716d155ca7e03b20f6fb85fc304 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Wed, 15 May 2024 20:44:13 +0100 Subject: [PATCH 1/2] feat: borsh serde --- Cargo.toml | 5 ++ src/external_trait_impls/borsh/hash_map.rs | 78 ++++++++++++++++++++++ src/external_trait_impls/borsh/mod.rs | 1 + src/external_trait_impls/mod.rs | 2 + 4 files changed, 86 insertions(+) create mode 100644 src/external_trait_impls/borsh/hash_map.rs create mode 100644 src/external_trait_impls/borsh/mod.rs diff --git a/Cargo.toml b/Cargo.toml index 7e50b438f..818d61038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,9 @@ allocator-api2 = { version = "0.2.9", optional = true, default-features = false, # Equivalent trait which can be shared with other hash table implementations. equivalent = { version = "1.0", optional = true, default-features = false } +# borsh serde +borsh = { version = "1.5.0", default-features = false, optional = true, features = ["derive"]} + [dev-dependencies] lazy_static = "1.4" rand = { version = "0.8.3", features = ["small_rng"] } @@ -66,6 +69,8 @@ raw = [] # time cost. inline-more = [] +borsh = ["dep:borsh"] + [package.metadata.docs.rs] features = ["nightly", "rayon", "serde", "raw"] rustdoc-args = ["--generate-link-to-definition"] diff --git a/src/external_trait_impls/borsh/hash_map.rs b/src/external_trait_impls/borsh/hash_map.rs new file mode 100644 index 000000000..8991affbc --- /dev/null +++ b/src/external_trait_impls/borsh/hash_map.rs @@ -0,0 +1,78 @@ +use crate::HashMap; + +use borsh::{ + io::{Read, Result, Write}, + BorshDeserialize, BorshSerialize, +}; + +impl BorshSerialize for HashMap { + fn serialize(&self, writer: &mut W) -> Result<()> { + // assuming hash may have some seed, + // as borsh is supposed by default to be deterministic, need to write it down + // if allocator is compile time, than one can just impl wrapper with zero bytes serde of it + self.hash_builder.serialize(writer)?; + // considering A stateless + self.len().serialize(writer)?; + for kv in self.iter() { + kv.serialize(writer)?; + } + Ok(()) + } +} + +impl< + K: BorshDeserialize + core::hash::Hash + Eq, + V: BorshDeserialize, + S: BorshDeserialize + core::hash::BuildHasher, + > BorshDeserialize for HashMap +{ + fn deserialize_reader(reader: &mut R) -> Result { + let hash_builder = S::deserialize_reader(reader)?; + let len = usize::deserialize_reader(reader)?; + let mut map = HashMap::with_capacity_and_hasher(len, hash_builder); + for _ in 0..len { + let (k, v) = <(K, V)>::deserialize_reader(reader)?; + // can use raw api here to init from memory, so can do it other time + map.insert(k, v); + } + Ok(map) + } +} + +#[cfg(test)] +mod tests { + use borsh::{BorshDeserialize, BorshSerialize}; + use std::vec::Vec; + + #[derive(Default, BorshDeserialize, BorshSerialize, Clone)] + struct NoHash; + + impl core::hash::BuildHasher for NoHash { + type Hasher = NoHash; + fn build_hasher(&self) -> NoHash { + Self + } + } + + impl core::hash::Hasher for NoHash { + fn finish(&self) -> u64 { + 42 + } + + fn write(&mut self, _bytes: &[u8]) {} + } + + #[test] + fn encdec() { + let mut map = crate::HashMap::<_, _, NoHash>::default(); + map.insert(1, 2); + map.insert(3, 4); + let mut buf = Vec::new(); + map.serialize(&mut buf).unwrap(); + let original = map.clone(); + map = crate::HashMap::<_, _, NoHash>::deserialize_reader(&mut &buf[..]).unwrap(); + assert_eq!(original[&1], map[&1]); + assert_eq!(original[&3], map[&3]); + assert_eq!(original.len(), map.len()); + } +} diff --git a/src/external_trait_impls/borsh/mod.rs b/src/external_trait_impls/borsh/mod.rs new file mode 100644 index 000000000..841e4b1a2 --- /dev/null +++ b/src/external_trait_impls/borsh/mod.rs @@ -0,0 +1 @@ +mod hash_map; diff --git a/src/external_trait_impls/mod.rs b/src/external_trait_impls/mod.rs index 01d386b04..bacb24f48 100644 --- a/src/external_trait_impls/mod.rs +++ b/src/external_trait_impls/mod.rs @@ -4,3 +4,5 @@ pub(crate) mod rayon; mod rkyv; #[cfg(feature = "serde")] mod serde; +#[cfg(feature = "borsh")] +mod borsh; From 734191c9182d5787330839ee7aa3d3de7c295119 Mon Sep 17 00:00:00 2001 From: dzmitry-lahoda Date: Wed, 15 May 2024 21:16:08 +0100 Subject: [PATCH 2/2] fmt --- src/external_trait_impls/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/external_trait_impls/mod.rs b/src/external_trait_impls/mod.rs index bacb24f48..452736f28 100644 --- a/src/external_trait_impls/mod.rs +++ b/src/external_trait_impls/mod.rs @@ -1,8 +1,8 @@ +#[cfg(feature = "borsh")] +mod borsh; #[cfg(feature = "rayon")] pub(crate) mod rayon; #[cfg(feature = "rkyv")] mod rkyv; #[cfg(feature = "serde")] mod serde; -#[cfg(feature = "borsh")] -mod borsh;