Skip to content

Commit f311e23

Browse files
committed
Implement borsh serialization routines
1 parent 255e587 commit f311e23

File tree

2 files changed

+101
-0
lines changed

2 files changed

+101
-0
lines changed

src/borsh.rs

+95
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#![cfg_attr(docsrs, doc(cfg(feature = "borsh")))]
2+
3+
use alloc::vec::Vec;
4+
use core::hash::BuildHasher;
5+
use core::hash::Hash;
6+
use core::iter::ExactSizeIterator;
7+
use core::mem::size_of;
8+
9+
use borsh::error::ERROR_ZST_FORBIDDEN;
10+
use borsh::io::{Error, ErrorKind, Read, Result, Write};
11+
use borsh::{BorshDeserialize, BorshSerialize};
12+
13+
use crate::map::IndexMap;
14+
use crate::set::IndexSet;
15+
16+
impl<K, V, H> BorshSerialize for IndexMap<K, V, H>
17+
where
18+
K: BorshSerialize,
19+
V: BorshSerialize,
20+
H: BuildHasher,
21+
{
22+
#[inline]
23+
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
24+
check_zst::<K>()?;
25+
26+
let iterator = self.iter();
27+
28+
u32::try_from(iterator.len())
29+
.map_err(|_| ErrorKind::InvalidData)?
30+
.serialize(writer)?;
31+
32+
for (key, value) in iterator {
33+
key.serialize(writer)?;
34+
value.serialize(writer)?;
35+
}
36+
37+
Ok(())
38+
}
39+
}
40+
41+
impl<K, V, H> BorshDeserialize for IndexMap<K, V, H>
42+
where
43+
K: BorshDeserialize + Eq + Hash,
44+
V: BorshDeserialize,
45+
H: BuildHasher + Default,
46+
{
47+
#[inline]
48+
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
49+
check_zst::<K>()?;
50+
let vec = <Vec<(K, V)>>::deserialize_reader(reader)?;
51+
Ok(vec.into_iter().collect::<IndexMap<K, V, H>>())
52+
}
53+
}
54+
55+
impl<T, H> BorshSerialize for IndexSet<T, H>
56+
where
57+
T: BorshSerialize,
58+
H: BuildHasher,
59+
{
60+
#[inline]
61+
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
62+
check_zst::<T>()?;
63+
64+
let iterator = self.iter();
65+
66+
u32::try_from(iterator.len())
67+
.map_err(|_| ErrorKind::InvalidData)?
68+
.serialize(writer)?;
69+
70+
for item in iterator {
71+
item.serialize(writer)?;
72+
}
73+
74+
Ok(())
75+
}
76+
}
77+
78+
impl<T, H> BorshDeserialize for IndexSet<T, H>
79+
where
80+
T: BorshDeserialize + Eq + Hash,
81+
H: BuildHasher + Default,
82+
{
83+
#[inline]
84+
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
85+
let vec = <Vec<T>>::deserialize_reader(reader)?;
86+
Ok(vec.into_iter().collect::<IndexSet<T, H>>())
87+
}
88+
}
89+
90+
fn check_zst<T>() -> Result<()> {
91+
if size_of::<T>() == 0 {
92+
return Err(Error::new(ErrorKind::InvalidData, ERROR_ZST_FORBIDDEN));
93+
}
94+
Ok(())
95+
}

src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
//! to [`IndexMap`] and [`IndexSet`]. Alternative implementations for
3636
//! (de)serializing [`IndexMap`] as an ordered sequence are available in the
3737
//! [`map::serde_seq`] module.
38+
//! * `borsh`: Adds implementations for [`BorshSerialize`] and [`BorshDeserialize`]
39+
//! to [`IndexMap`] and [`IndexSet`].
3840
//! * `arbitrary`: Adds implementations for the [`arbitrary::Arbitrary`] trait
3941
//! to [`IndexMap`] and [`IndexSet`].
4042
//! * `quickcheck`: Adds implementations for the [`quickcheck::Arbitrary`] trait
@@ -46,6 +48,8 @@
4648
//! [`no_std`]: #no-standard-library-targets
4749
//! [`Serialize`]: `::serde::Serialize`
4850
//! [`Deserialize`]: `::serde::Deserialize`
51+
//! [`BorshSerialize`]: `::borsh::BorshSerialize`
52+
//! [`BorshDeserialize`]: `::borsh::BorshDeserialize`
4953
//! [`arbitrary::Arbitrary`]: `::arbitrary::Arbitrary`
5054
//! [`quickcheck::Arbitrary`]: `::quickcheck::Arbitrary`
5155
//!
@@ -110,6 +114,8 @@ use alloc::vec::{self, Vec};
110114
mod arbitrary;
111115
#[macro_use]
112116
mod macros;
117+
#[cfg(feature = "borsh")]
118+
mod borsh;
113119
mod mutable_keys;
114120
#[cfg(feature = "serde")]
115121
mod serde;

0 commit comments

Comments
 (0)