Repository: near/borsh-rs
Pull request #132 (2023-03-21 16:28:26)

Add optional bytes/bytesmut support


Patch:
diff --git a/borsh/Cargo.toml b/borsh/Cargo.toml
index 4f1b2f0d..141609ad 100644
--- a/borsh/Cargo.toml
+++ b/borsh/Cargo.toml
@@ -23,6 +23,12 @@ path = "src/generate_schema_schema.rs"
 [dependencies]
 borsh-derive = { path = "../borsh-derive" }
 hashbrown = ">=0.11,<0.14"
+bytes = { version = "1", optional = true }
+
+[dev-dependencies]
+bytes = "1"
+# Enable the "bytes" feature in integ tests: https://github.com/rust-lang/cargo/issues/2911#issuecomment-1464060655
+borsh = { path = ".", features = ["bytes"] }
 
 [features]
 default = ["std"]
diff --git a/borsh/src/de/mod.rs b/borsh/src/de/mod.rs
index 8798a5bc..862b1632 100644
--- a/borsh/src/de/mod.rs
+++ b/borsh/src/de/mod.rs
@@ -6,6 +6,9 @@ use core::{
     mem::{forget, size_of},
 };
 
+#[cfg(any(test, feature = "bytes"))]
+use bytes::{BufMut, BytesMut};
+
 use crate::maybestd::{
     borrow::{Borrow, Cow, ToOwned},
     boxed::Box,
@@ -400,6 +403,28 @@ where
     }
 }
 
+#[cfg(any(test, feature = "bytes"))]
+impl BorshDeserialize for bytes::Bytes {
+    #[inline]
+    fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
+        let vec = <Vec<u8>>::deserialize_reader(reader)?;
+        Ok(vec.into())
+    }
+}
+
+#[cfg(any(test, feature = "bytes"))]
+impl BorshDeserialize for bytes::BytesMut {
+    #[inline]
+    fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
+        let len = u32::deserialize_reader(reader)?;
+        let mut out = BytesMut::with_capacity(hint::cautious::<u8>(len));
+        for _ in 0..len {
+            out.put_u8(u8::deserialize_reader(reader)?);
+        }
+        Ok(out)
+    }
+}
+
 impl<T> BorshDeserialize for Cow<'_, T>
 where
     T: ToOwned + ?Sized,
diff --git a/borsh/src/ser/mod.rs b/borsh/src/ser/mod.rs
index b905db07..56eb628c 100644
--- a/borsh/src/ser/mod.rs
+++ b/borsh/src/ser/mod.rs
@@ -271,6 +271,22 @@ where
     }
 }
 
+#[cfg(any(test, feature = "bytes"))]
+impl BorshSerialize for bytes::Bytes {
+    #[inline]
+    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
+        self.as_ref().serialize(writer)
+    }
+}
+
+#[cfg(any(test, feature = "bytes"))]
+impl BorshSerialize for bytes::BytesMut {
+    #[inline]
+    fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
+        self.as_ref().serialize(writer)
+    }
+}
+
 impl<T> BorshSerialize for VecDeque<T>
 where
     T: BorshSerialize,


Test patch:
diff --git a/borsh/tests/test_simple_structs.rs b/borsh/tests/test_simple_structs.rs
index ce484828..9633e6c4 100644
--- a/borsh/tests/test_simple_structs.rs
+++ b/borsh/tests/test_simple_structs.rs
@@ -1,5 +1,6 @@
 use borsh::maybestd::collections::{BTreeMap, BTreeSet, HashMap, HashSet, LinkedList, VecDeque};
 use borsh::{BorshDeserialize, BorshSerialize};
+use bytes::{Bytes, BytesMut};
 
 #[derive(BorshSerialize, BorshDeserialize, PartialEq, Debug)]
 #[borsh_init(init)]
@@ -15,6 +16,8 @@ struct A<'a> {
     btree_set_u64: BTreeSet<u64>,
     linked_list_string: LinkedList<String>,
     vec_deque_u64: VecDeque<u64>,
+    bytes: Bytes,
+    bytes_mut: BytesMut,
     v: Vec<String>,
     w: Box<[u8]>,
     box_str: Box<str>,
@@ -98,6 +101,8 @@ fn test_simple_struct() {
         btree_set_u64: set.clone().into_iter().collect(),
         linked_list_string: vec!["a".to_string(), "b".to_string()].into_iter().collect(),
         vec_deque_u64: vec![1, 2, 3].into_iter().collect(),
+        bytes: vec![5, 4, 3, 2, 1].into(),
+        bytes_mut: BytesMut::from(&[1, 2, 3, 4, 5][..]),
         v: vec!["qwe".to_string(), "zxc".to_string()],
         w: vec![0].into_boxed_slice(),
         box_str: Box::from("asd"),
@@ -131,6 +136,8 @@ fn test_simple_struct() {
         btree_set_u64: set.clone().into_iter().collect(),
         linked_list_string: vec!["a".to_string(), "b".to_string()].into_iter().collect(),
         vec_deque_u64: vec![1, 2, 3].into_iter().collect(),
+        bytes: vec![5, 4, 3, 2, 1].into(),
+        bytes_mut: BytesMut::from(&[1, 2, 3, 4, 5][..]),
         v: a.v.clone(),
         w: a.w.clone(),
         box_str: Box::from("asd"),