Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: impl BorshSchema for Rc and Arc; add doc for rc feature #268

Merged
merged 2 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ cargo test
cargo test --features unstable__schema,ascii --test test_ascii_strings
cargo test --features derive
cargo test --features unstable__schema
cargo test --test test_rc --features rc
cargo test --test test_rc --features unstable__schema,rc
cargo test --test test_hash_map --test test_btree_map --features de_strict_order

cargo test --no-default-features
cargo test --no-default-features --features unstable__schema,ascii --test test_ascii_strings
cargo test --no-default-features --features derive
cargo test --no-default-features --features unstable__schema
cargo test --no-default-features --test test_rc --features rc
cargo test --no-default-features --test test_rc --features unstable__schema,rc
cargo test --no-default-features --features hashbrown
popd
pushd borsh-derive
Expand Down
5 changes: 4 additions & 1 deletion borsh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,16 @@ borsh = { path = ".", default_features = false, features = ["bytes", "bson"] }
insta = "1.29.0"

[package.metadata.docs.rs]
features = ["derive", "unstable__schema"]
features = ["derive", "unstable__schema", "rc"]
targets = ["x86_64-unknown-linux-gnu"]

[features]
default = ["std"]
derive = ["borsh-derive"]
unstable__schema = ["derive", "borsh-derive/schema"]
std = []
# Opt into impls for Rc<T> and Arc<T>. Serializing and deserializing these types
# does not preserve identity and may result in multiple copies of the same data.
# Be sure that this is what you want before enabling this feature.
rc = []
de_strict_order = []
49 changes: 33 additions & 16 deletions borsh/src/de/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ use crate::__private::maybestd::{
};
use crate::io::{Error, ErrorKind, Read, Result};

#[cfg(feature = "rc")]
use crate::__private::maybestd::{rc::Rc, sync::Arc};
use crate::error::check_zst;

mod hint;
Expand Down Expand Up @@ -883,23 +881,42 @@ impl_range!(RangeFrom, start.., start);
impl_range!(RangeTo, ..end, end);
impl_range!(RangeToInclusive, ..=end, end);

/// Module is available if borsh is built with `features = ["rc"]`.
#[cfg(feature = "rc")]
impl<T: ?Sized> BorshDeserialize for Rc<T>
where
Box<T>: BorshDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Box::<T>::deserialize_reader(reader)?.into())
pub mod rc {
//!
//! Module defines [BorshDeserialize] implementation for
//! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc).
use crate::__private::maybestd::{boxed::Box, rc::Rc, sync::Arc};
use crate::io::{Read, Result};
use crate::BorshDeserialize;

/// This impl requires the [`"rc"`] Cargo feature of borsh.
///
/// Deserializing a data structure containing `Rc` will not attempt to
/// deduplicate `Rc` references to the same data. Every deserialized `Rc`
/// will end up with a strong count of 1.
impl<T: ?Sized> BorshDeserialize for Rc<T>
where
Box<T>: BorshDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Box::<T>::deserialize_reader(reader)?.into())
}
}
}

#[cfg(feature = "rc")]
impl<T: ?Sized> BorshDeserialize for Arc<T>
where
Box<T>: BorshDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Box::<T>::deserialize_reader(reader)?.into())
/// This impl requires the [`"rc"`] Cargo feature of borsh.
///
/// Deserializing a data structure containing `Arc` will not attempt to
/// deduplicate `Arc` references to the same data. Every deserialized `Arc`
/// will end up with a strong count of 1.
impl<T: ?Sized> BorshDeserialize for Arc<T>
where
Box<T>: BorshDeserialize,
{
fn deserialize_reader<R: Read>(reader: &mut R) -> Result<Self> {
Ok(Box::<T>::deserialize_reader(reader)?.into())
}
}
}

Expand Down
3 changes: 3 additions & 0 deletions borsh/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
Gates implementation of [BorshSerialize] and [BorshDeserialize]
for [`Rc<T>`](std::rc::Rc)/[`Arc<T>`](std::sync::Arc) respectively.
In `no_std` setting `Rc`/`Arc` are pulled from `alloc` crate.
Serializing and deserializing these types
does not preserve identity and may result in multiple copies of the same data.
Be sure that this is what you want before enabling this feature.
* **hashbrown** -
Pulls in [HashMap](std::collections::HashMap)/[HashSet](std::collections::HashSet) when no `std` is available.
This feature is set to be mutually exclusive with **std** feature.
Expand Down
38 changes: 38 additions & 0 deletions borsh/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,44 @@ where
T::declaration()
}
}
/// Module is available if borsh is built with `features = ["rc"]`.
#[cfg(feature = "rc")]
pub mod rc {
//!
//! Module defines [BorshSchema] implementation for
//! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc).
use crate::BorshSchema;

use super::{Declaration, Definition};
use crate::__private::maybestd::collections::BTreeMap;
use crate::__private::maybestd::{rc::Rc, sync::Arc};

impl<T> BorshSchema for Rc<T>
where
T: BorshSchema + ?Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}

fn declaration() -> Declaration {
T::declaration()
}
}

impl<T> BorshSchema for Arc<T>
where
T: BorshSchema + ?Sized,
{
fn add_definitions_recursively(definitions: &mut BTreeMap<Declaration, Definition>) {
T::add_definitions_recursively(definitions);
}

fn declaration() -> Declaration {
T::declaration()
}
}
}

macro_rules! impl_for_renamed_primitives {
($($ty: ty : $name: ident => $size: expr);+) => {
Expand Down
40 changes: 29 additions & 11 deletions borsh/src/ser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ use crate::__private::maybestd::{
use crate::error::check_zst;
use crate::io::{Error, ErrorKind, Result, Write};

#[cfg(feature = "rc")]
use crate::__private::maybestd::{rc::Rc, sync::Arc};

pub(crate) mod helpers;

const FLOAT_NAN_ERR: &str = "For portability reasons we do not allow to serialize NaNs.";
Expand Down Expand Up @@ -600,17 +597,38 @@ impl_range!(RangeFrom, this, &this.start);
impl_range!(RangeTo, this, &this.end);
impl_range!(RangeToInclusive, this, &this.end);

/// Module is available if borsh is built with `features = ["rc"]`.
#[cfg(feature = "rc")]
impl<T: BorshSerialize + ?Sized> BorshSerialize for Rc<T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
(**self).serialize(writer)
pub mod rc {
//!
//! Module defines [BorshSerialize] implementation for
//! [alloc::rc::Rc](std::rc::Rc) and [alloc::sync::Arc](std::sync::Arc).
use crate::__private::maybestd::{rc::Rc, sync::Arc};
use crate::io::{Result, Write};
use crate::BorshSerialize;

/// This impl requires the [`"rc"`] Cargo feature of borsh.
///
/// Serializing a data structure containing `Rc` will serialize a copy of
/// the contents of the `Rc` each time the `Rc` is referenced within the
/// data structure. Serialization will not attempt to deduplicate these
/// repeated data.
impl<T: BorshSerialize + ?Sized> BorshSerialize for Rc<T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
(**self).serialize(writer)
}
}
}

#[cfg(feature = "rc")]
impl<T: BorshSerialize + ?Sized> BorshSerialize for Arc<T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
(**self).serialize(writer)
/// This impl requires the [`"rc"`] Cargo feature of borsh.
///
/// Serializing a data structure containing `Arc` will serialize a copy of
/// the contents of the `Arc` each time the `Arc` is referenced within the
/// data structure. Serialization will not attempt to deduplicate these
/// repeated data.
impl<T: BorshSerialize + ?Sized> BorshSerialize for Arc<T> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<()> {
(**self).serialize(writer)
}
}
}

Expand Down
73 changes: 72 additions & 1 deletion borsh/tests/test_rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#[cfg(feature = "std")]
pub use std::{rc, sync};

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
pub use alloc::{rc, sync};
Expand Down Expand Up @@ -44,3 +43,75 @@ fn test_slice_arc() {
let deserialized = from_slice::<sync::Arc<[i32]>>(&serialized).unwrap();
assert_eq!(original, &*deserialized);
}

#[cfg(feature = "unstable__schema")]
mod schema {
use super::{rc, sync};
use alloc::{
collections::BTreeMap,
string::{String, ToString},
};
use borsh::schema::{BorshSchema, Definition};
macro_rules! map(
() => { BTreeMap::new() };
{ $($key:expr => $value:expr),+ } => {
{
let mut m = BTreeMap::new();
$(
m.insert($key.to_string(), $value);
)+
m
}
};
);
fn common_map_i32() -> BTreeMap<String, Definition> {
map! {

"i32" => Definition::Primitive(4)
}
}

fn common_map_slice_i32() -> BTreeMap<String, Definition> {
map! {
"Vec<i32>" => Definition::Sequence {
length_width: Definition::DEFAULT_LENGTH_WIDTH,
length_range: Definition::DEFAULT_LENGTH_RANGE,
elements: "i32".to_string()
},
"i32" => Definition::Primitive(4)
}
}

#[test]
fn test_rc() {
assert_eq!("i32", <rc::Rc<i32> as BorshSchema>::declaration());

let mut actual_defs = map!();
<rc::Rc<i32> as BorshSchema>::add_definitions_recursively(&mut actual_defs);
assert_eq!(common_map_i32(), actual_defs);
}

#[test]
fn test_slice_rc() {
assert_eq!("Vec<i32>", <rc::Rc<[i32]> as BorshSchema>::declaration());
let mut actual_defs = map!();
<rc::Rc<[i32]> as BorshSchema>::add_definitions_recursively(&mut actual_defs);
assert_eq!(common_map_slice_i32(), actual_defs);
}

#[test]
fn test_arc() {
assert_eq!("i32", <sync::Arc<i32> as BorshSchema>::declaration());
let mut actual_defs = map!();
<sync::Arc<i32> as BorshSchema>::add_definitions_recursively(&mut actual_defs);
assert_eq!(common_map_i32(), actual_defs);
}

#[test]
fn test_slice_arc() {
assert_eq!("Vec<i32>", <sync::Arc<[i32]> as BorshSchema>::declaration());
let mut actual_defs = map!();
<sync::Arc<[i32]> as BorshSchema>::add_definitions_recursively(&mut actual_defs);
assert_eq!(common_map_slice_i32(), actual_defs);
}
}
Loading