Improve optional support for borsh serialization
- Do not allocate when deserializing ArrayString - Serialize length as u32, not as u64, to be consistent with serialization of [T] and str - Add tests
This commit is contained in:
@@ -18,7 +18,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- rust: 1.51.0 # MSRV
|
||||
features: serde
|
||||
features: serde, borsh
|
||||
experimental: false
|
||||
- rust: stable
|
||||
features:
|
||||
@@ -28,7 +28,7 @@ jobs:
|
||||
features: serde
|
||||
experimental: false
|
||||
- rust: nightly
|
||||
features: serde, zeroize
|
||||
features: serde, borsh, zeroize
|
||||
experimental: false
|
||||
|
||||
steps:
|
||||
|
||||
+15
-6
@@ -640,13 +640,22 @@ impl<const CAP: usize> borsh::BorshSerialize for ArrayString<CAP> {
|
||||
/// Requires crate feature `"borsh"`
|
||||
impl<const CAP: usize> borsh::BorshDeserialize for ArrayString<CAP> {
|
||||
fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
|
||||
let s = <String as borsh::BorshDeserialize>::deserialize_reader(reader)?;
|
||||
ArrayString::from(&s).map_err(|_| {
|
||||
borsh::io::Error::new(
|
||||
let len = <u32 as borsh::BorshDeserialize>::deserialize_reader(reader)? as usize;
|
||||
if len > CAP {
|
||||
return Err(borsh::io::Error::new(
|
||||
borsh::io::ErrorKind::InvalidData,
|
||||
format!("expected a string no more than {} bytes long", CAP),
|
||||
)
|
||||
})
|
||||
format!("Expected a string no more than {} bytes long", CAP),
|
||||
))
|
||||
}
|
||||
|
||||
let mut buf = [0u8; CAP];
|
||||
let buf = &mut buf[..len];
|
||||
reader.read_exact(buf)?;
|
||||
|
||||
let s = str::from_utf8(&buf).map_err(|err| {
|
||||
borsh::io::Error::new(borsh::io::ErrorKind::InvalidData, err.to_string())
|
||||
})?;
|
||||
Ok(Self::from(s).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-8
@@ -1309,12 +1309,7 @@ where
|
||||
T: borsh::BorshSerialize,
|
||||
{
|
||||
fn serialize<W: borsh::io::Write>(&self, writer: &mut W) -> borsh::io::Result<()> {
|
||||
let vs = self.as_slice();
|
||||
<usize as borsh::BorshSerialize>::serialize(&vs.len(), writer)?;
|
||||
for elem in vs {
|
||||
<T as borsh::BorshSerialize>::serialize(elem, writer)?;
|
||||
}
|
||||
Ok(())
|
||||
<[T] as borsh::BorshSerialize>::serialize(self.as_slice(), writer)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1326,13 +1321,13 @@ where
|
||||
{
|
||||
fn deserialize_reader<R: borsh::io::Read>(reader: &mut R) -> borsh::io::Result<Self> {
|
||||
let mut values = Self::new();
|
||||
let len = <usize as borsh::BorshDeserialize>::deserialize_reader(reader)?;
|
||||
let len = <u32 as borsh::BorshDeserialize>::deserialize_reader(reader)?;
|
||||
for _ in 0..len {
|
||||
let elem = <T as borsh::BorshDeserialize>::deserialize_reader(reader)?;
|
||||
if let Err(_) = values.try_push(elem) {
|
||||
return Err(borsh::io::Error::new(
|
||||
borsh::io::ErrorKind::InvalidData,
|
||||
format!("expected an array with no more than {} items", CAP),
|
||||
format!("Expected an array with no more than {} items", CAP),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
#![cfg(feature = "borsh")]
|
||||
use std::fmt;
|
||||
extern crate arrayvec;
|
||||
extern crate borsh;
|
||||
|
||||
fn assert_ser<T: borsh::BorshSerialize>(v: &T, expected_bytes: &[u8]) {
|
||||
let mut actual_bytes = Vec::new();
|
||||
v.serialize(&mut actual_bytes).unwrap();
|
||||
assert_eq!(actual_bytes, expected_bytes);
|
||||
}
|
||||
|
||||
fn assert_roundtrip<T: borsh::BorshSerialize + borsh::BorshDeserialize + PartialEq + fmt::Debug>(v: &T) {
|
||||
let mut bytes = Vec::new();
|
||||
v.serialize(&mut bytes).unwrap();
|
||||
let v_de = T::try_from_slice(&bytes).unwrap();
|
||||
assert_eq!(*v, v_de);
|
||||
}
|
||||
|
||||
mod array_vec {
|
||||
use arrayvec::ArrayVec;
|
||||
use super::{assert_ser, assert_roundtrip};
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let vec = ArrayVec::<u32, 0>::new();
|
||||
assert_ser(&vec, b"\0\0\0\0");
|
||||
assert_roundtrip(&vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full() {
|
||||
let mut vec = ArrayVec::<u32, 3>::new();
|
||||
vec.push(0xdeadbeef);
|
||||
vec.push(0x123);
|
||||
vec.push(0x456);
|
||||
assert_ser(&vec, b"\x03\0\0\0\xef\xbe\xad\xde\x23\x01\0\0\x56\x04\0\0");
|
||||
assert_roundtrip(&vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_free_capacity() {
|
||||
let mut vec = ArrayVec::<u32, 3>::new();
|
||||
vec.push(0xdeadbeef);
|
||||
assert_ser(&vec, b"\x01\0\0\0\xef\xbe\xad\xde");
|
||||
assert_roundtrip(&vec);
|
||||
}
|
||||
}
|
||||
|
||||
mod array_string {
|
||||
use arrayvec::ArrayString;
|
||||
use super::{assert_ser, assert_roundtrip};
|
||||
|
||||
#[test]
|
||||
fn test_empty() {
|
||||
let string = ArrayString::<0>::new();
|
||||
assert_ser(&string, b"\0\0\0\0");
|
||||
assert_roundtrip(&string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_full() {
|
||||
let string = ArrayString::from_byte_string(b"hello world").unwrap();
|
||||
assert_ser(&string, b"\x0b\0\0\0hello world");
|
||||
assert_roundtrip(&string);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_free_capacity() {
|
||||
let string = ArrayString::<16>::from("hello world").unwrap();
|
||||
assert_ser(&string, b"\x0b\0\0\0hello world");
|
||||
assert_roundtrip(&string);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user