Skip to content

Commit

Permalink
Add serialisation for range types
Browse files Browse the repository at this point in the history
  • Loading branch information
mina86 committed Sep 8, 2023
1 parent 09c9295 commit 771bccd
Show file tree
Hide file tree
Showing 5 changed files with 182 additions and 52 deletions.
51 changes: 31 additions & 20 deletions borsh/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,19 +315,6 @@ impl BorshDeserialize for bool {
}
}

impl<T> BorshDeserialize for core::ops::Range<T>
where
T: BorshDeserialize,
{
#[inline]
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Self {
start: T::deserialize_reader(reader)?,
end: T::deserialize_reader(reader)?,
})
}
}

impl<T> BorshDeserialize for Option<T>
where
T: BorshDeserialize,
Expand Down Expand Up @@ -476,7 +463,7 @@ where
#[cfg(hash_collections)]
pub mod hashes {
//!
//! Module defines [BorshDeserialize](crate::de::BorshDeserialize) implementation for
//! Module defines [BorshDeserialize](crate::de::BorshDeserialize) implementation for
//! [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet).
use core::hash::{BuildHasher, Hash};

Expand Down Expand Up @@ -802,13 +789,16 @@ fn array_deserialization_doesnt_leak() {
}
}

impl BorshDeserialize for () {
fn deserialize_reader<R: Read>(_reader: &mut R) -> Result<Self> {
Ok(())
}
}

macro_rules! impl_tuple {
(@unit $name:ty) => {
impl BorshDeserialize for $name {
#[inline]
fn deserialize_reader<R: Read>(_reader: &mut R) -> Result<Self> {
Ok(<$name>::default())
}
}
};

($($name:ident)+) => {
impl<$($name),+> BorshDeserialize for ($($name,)+)
where $($name: BorshDeserialize,)+
Expand All @@ -822,6 +812,9 @@ macro_rules! impl_tuple {
};
}

impl_tuple!(@unit ());
impl_tuple!(@unit core::ops::RangeFull);

impl_tuple!(T0);
impl_tuple!(T0 T1);
impl_tuple!(T0 T1 T2);
Expand All @@ -843,6 +836,24 @@ impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17);
impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18);
impl_tuple!(T0 T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 T16 T17 T18 T19);

macro_rules! impl_range {
($typ:ident, $make:expr $(, $side:ident)*) => {
impl<T: BorshDeserialize> BorshDeserialize for core::ops::$typ<T> {
#[inline]
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
let ($($side,)*) = <_>::deserialize_reader(reader)?;
Ok($make)
}
}
};
}

impl_range!(Range, start..end, start, end);
impl_range!(RangeInclusive, start..=end, start, end);
impl_range!(RangeFrom, start.., start);
impl_range!(RangeTo, ..end, end);
impl_range!(RangeToInclusive, ..=end, end);

#[cfg(feature = "rc")]
impl<T: ?Sized> BorshDeserialize for Rc<T>
where
Expand Down
84 changes: 70 additions & 14 deletions borsh/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,30 +204,22 @@ where
}
}

impl BorshSchema for () {
fn add_definitions_recursively(_definitions: &mut BTreeMap<Declaration, Definition>) {}

fn declaration() -> Declaration {
"nil".to_string()
}
}

macro_rules! impl_for_renamed_primitives {
($($type: ident : $name: ident)+) => {
($($type: ty : $name: ident)+) => {
$(
impl BorshSchema for $type {
#[inline]
fn add_definitions_recursively(_definitions: &mut BTreeMap<Declaration, Definition>) {}
fn declaration() -> Declaration {
stringify!($name).to_string()
}
#[inline]
fn declaration() -> Declaration { stringify!($name).into() }
}
)+
};
}

macro_rules! impl_for_primitives {
($($type: ident)+) => {
impl_for_renamed_primitives!{$($type : $type)+}
impl_for_renamed_primitives!{$($type : $type)+}
};
}

Expand All @@ -237,6 +229,34 @@ impl_for_renamed_primitives!(str: string);
impl_for_renamed_primitives!(isize: i64);
impl_for_renamed_primitives!(usize: u64);

impl_for_renamed_primitives!((): nil);
impl_for_renamed_primitives!(core::ops::RangeFull: nil);

macro_rules! impl_for_range {
($typ:ident $(, $name:ident)*) => {
impl<T: BorshSchema> BorshSchema for core::ops::$typ<T> {
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
let decl = T::declaration();
let fields = Fields::NamedFields(vec![$(
(FieldName::from(stringify!($name)), decl.clone())
),*]);
let def = Definition::Struct { fields };
add_definition(Self::declaration(), def, definitions);
T::add_definitions_recursively(definitions);
}
fn declaration() -> Declaration {
format!("{}<{}>", stringify!($typ), T::declaration())
}
}
};
}

impl_for_range!(Range, start, end);
impl_for_range!(RangeInclusive, start, end);
impl_for_range!(RangeFrom, start);
impl_for_range!(RangeTo, end);
impl_for_range!(RangeToInclusive, end);

impl<T, const N: usize> BorshSchema for [T; N]
where
T: BorshSchema,
Expand Down Expand Up @@ -333,7 +353,7 @@ where
#[cfg(hash_collections)]
pub mod hashes {
//!
//! Module defines [BorshSchema](crate::schema::BorshSchema) implementation for
//! Module defines [BorshSchema](crate::schema::BorshSchema) implementation for
//! [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet).
use crate::BorshSchema;

Expand Down Expand Up @@ -712,4 +732,40 @@ mod tests {
let phantom_declaration = PhantomData::<Vec<u8>>::declaration();
assert_eq!("nil", phantom_declaration);
}

#[test]
fn range() {
assert_eq!("nil", <core::ops::RangeFull>::declaration());

let actual_name = <core::ops::Range<u64>>::declaration();
let mut actual_defs = map!();
<core::ops::Range<u64>>::add_definitions_recursively(&mut actual_defs);
assert_eq!("Range<u64>", actual_name);
assert_eq!(
map! {
"Range<u64>" => Definition::Struct {
fields: Fields::NamedFields(vec![
("start".into(), "u64".into()),
("end".into(), "u64".into()),
])
}
},
actual_defs
);

let actual_name = <core::ops::RangeTo<u64>>::declaration();
let mut actual_defs = map!();
<core::ops::RangeTo<u64>>::add_definitions_recursively(&mut actual_defs);
assert_eq!("RangeTo<u64>", actual_name);
assert_eq!(
map! {
"RangeTo<u64>" => Definition::Struct {
fields: Fields::NamedFields(vec![
("end".into(), "u64".into()),
])
}
},
actual_defs
);
}
}
50 changes: 32 additions & 18 deletions borsh/src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,17 +170,6 @@ impl BorshSerialize for bool {
}
}

impl<T> BorshSerialize for core::ops::Range<T>
where
T: BorshSerialize,
{
#[inline]
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
self.start.serialize(writer)?;
self.end.serialize(writer)
}
}

impl<T> BorshSerialize for Option<T>
where
T: BorshSerialize,
Expand Down Expand Up @@ -349,7 +338,7 @@ where
#[cfg(hash_collections)]
pub mod hashes {
//!
//! Module defines [BorshSerialize](crate::ser::BorshSerialize) implementation for
//! Module defines [BorshSerialize](crate::ser::BorshSerialize) implementation for
//! [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet).
use crate::__private::maybestd::vec::Vec;
use crate::error::check_zst;
Expand Down Expand Up @@ -524,13 +513,16 @@ where
}
}

impl BorshSerialize for () {
fn serialize<W: Write>(&self, _writer: &mut W) -> Result<()> {
Ok(())
}
}

macro_rules! impl_tuple {
(@unit $name:ty) => {
impl BorshSerialize for $name {
#[inline]
fn serialize<W: Write>(&self, _writer: &mut W) -> Result<()> {
Ok(())
}
}
};

($($idx:tt $name:ident)+) => {
impl<$($name),+> BorshSerialize for ($($name,)+)
where $($name: BorshSerialize,)+
Expand All @@ -544,6 +536,9 @@ macro_rules! impl_tuple {
};
}

impl_tuple!(@unit ());
impl_tuple!(@unit core::ops::RangeFull);

impl_tuple!(0 T0);
impl_tuple!(0 T0 1 T1);
impl_tuple!(0 T0 1 T1 2 T2);
Expand All @@ -565,6 +560,25 @@ impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T
impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16 17 T17 18 T18);
impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15 16 T16 17 T17 18 T18 19 T19);

macro_rules! impl_range {
($typ:ident, $this:ident $(, $field:expr)*) => {
impl<T: BorshSerialize> BorshSerialize for core::ops::$typ<T> {
#[inline]
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
let $this = self;
$( $field.serialize(writer)?; )*
Ok(())
}
}
};
}

impl_range!(Range, this, &this.start, &this.end);
impl_range!(RangeInclusive, this, this.start(), this.end());
impl_range!(RangeFrom, this, &this.start);
impl_range!(RangeTo, this, &this.end);
impl_range!(RangeToInclusive, this, &this.end);

#[cfg(feature = "rc")]
impl<T: BorshSerialize + ?Sized> BorshSerialize for Rc<T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
Expand Down
34 changes: 34 additions & 0 deletions borsh/tests/snapshots/test_range__ranges.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
source: borsh/tests/test_range.rs
expression: encoded
---
[
1,
0,
0,
0,
2,
0,
0,
0,
3,
0,
0,
0,
4,
0,
0,
0,
5,
0,
0,
0,
6,
0,
0,
0,
7,
0,
0,
0,
]
15 changes: 15 additions & 0 deletions borsh/tests/test_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::format;

#[test]
fn test_ranges() {
let want = (1..2, 3..=4, 5.., ..6, ..=7, ..);

let encoded = borsh::to_vec(&want).unwrap();
#[cfg(feature = "std")]
insta::assert_debug_snapshot!(encoded);

let got = borsh::from_slice(&encoded).unwrap();
assert_eq!(want, got);
}

0 comments on commit 771bccd

Please sign in to comment.