Skip to content
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
3 changes: 3 additions & 0 deletions bounded-collections/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ The format is based on [Keep a Changelog].

[Keep a Changelog]: http://keepachangelog.com/en/1.0.0/

## [0.1.5] - 2023-02-13
- Fixed `Hash` impl (previously it could not be used in practice, because the size bound was required to also implement `Hash`).

## [0.1.4] - 2023-01-28
- Fixed unnecessary decoding and allocations for bounded types, when the decoded length is greater than the allowed bound.
- Add `Hash` derivation (when `feature = "std"`) for bounded types.
Expand Down
2 changes: 1 addition & 1 deletion bounded-collections/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bounded-collections"
version = "0.1.4"
version = "0.1.5"
authors = ["Parity Technologies <[email protected]>"]
license = "MIT OR Apache-2.0"
homepage = "https://github.com/paritytech/parity-common"
Expand Down
22 changes: 21 additions & 1 deletion bounded-collections/src/bounded_btree_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use core::{borrow::Borrow, marker::PhantomData, ops::Deref};
///
/// Unlike a standard `BTreeMap`, there is an enforced upper limit to the number of items in the
/// map. All internal operations ensure this bound is respected.
#[cfg_attr(feature = "std", derive(Hash))]
#[derive(Encode, scale_info::TypeInfo)]
#[scale_info(skip_type_params(S))]
pub struct BoundedBTreeMap<K, V, S>(BTreeMap<K, V>, PhantomData<S>);
Expand Down Expand Up @@ -237,6 +236,15 @@ where
}
}

// Custom implementation of `Hash` since deriving it would require all generic bounds to also
// implement it.
#[cfg(feature = "std")]
impl<K: std::hash::Hash, V: std::hash::Hash, S> std::hash::Hash for BoundedBTreeMap<K, V, S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}

impl<K, V, S1, S2> PartialEq<BoundedBTreeMap<K, V, S1>> for BoundedBTreeMap<K, V, S2>
where
BTreeMap<K, V>: PartialEq,
Expand Down Expand Up @@ -641,4 +649,16 @@ mod test {

assert_eq!(Ok(b2), b1.try_map(|(_, v)| (v as u16).checked_mul(100_u16).ok_or("overflow")));
}

// Just a test that structs containing `BoundedBTreeMap` can derive `Hash`. (This was broken
// when it was deriving `Hash`).
#[test]
#[cfg(feature = "std")]
fn container_can_derive_hash() {
#[derive(Hash)]
struct Foo {
bar: u8,
map: BoundedBTreeMap<String, usize, ConstU32<16>>,
}
}
}
22 changes: 21 additions & 1 deletion bounded-collections/src/bounded_btree_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ use core::{borrow::Borrow, marker::PhantomData, ops::Deref};
///
/// Unlike a standard `BTreeSet`, there is an enforced upper limit to the number of items in the
/// set. All internal operations ensure this bound is respected.
#[cfg_attr(feature = "std", derive(Hash))]
#[derive(Encode, scale_info::TypeInfo)]
#[scale_info(skip_type_params(S))]
pub struct BoundedBTreeSet<T, S>(BTreeSet<T>, PhantomData<S>);
Expand Down Expand Up @@ -176,6 +175,15 @@ where
}
}

// Custom implementation of `Hash` since deriving it would require all generic bounds to also
// implement it.
#[cfg(feature = "std")]
impl<T: std::hash::Hash, S> std::hash::Hash for BoundedBTreeSet<T, S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}

impl<T, S1, S2> PartialEq<BoundedBTreeSet<T, S1>> for BoundedBTreeSet<T, S2>
where
BTreeSet<T>: PartialEq,
Expand Down Expand Up @@ -502,4 +510,16 @@ mod test {
let b2: Result<BoundedBTreeSet<u32, ConstU32<1>>, _> = b1.iter().map(|k| k + 1).skip(2).try_collect();
assert!(b2.is_err());
}

// Just a test that structs containing `BoundedBTreeSet` can derive `Hash`. (This was broken
// when it was deriving `Hash`).
#[test]
#[cfg(feature = "std")]
fn container_can_derive_hash() {
#[derive(Hash)]
struct Foo {
bar: u8,
set: BoundedBTreeSet<String, ConstU32<16>>,
}
}
}
36 changes: 33 additions & 3 deletions bounded-collections/src/bounded_vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ use serde::{
///
/// As the name suggests, the length of the queue is always bounded. All internal operations ensure
/// this bound is respected.
#[cfg_attr(feature = "std", derive(Hash, Serialize), serde(transparent))]
#[cfg_attr(feature = "std", derive(Serialize), serde(transparent))]
#[derive(Encode, scale_info::TypeInfo)]
#[scale_info(skip_type_params(S))]
pub struct BoundedVec<T, S>(pub(super) Vec<T>, #[cfg_attr(feature = "std", serde(skip_serializing))] PhantomData<S>);
Expand Down Expand Up @@ -108,7 +108,6 @@ where
/// A bounded slice.
///
/// Similar to a `BoundedVec`, but not owned and cannot be decoded.
#[cfg_attr(feature = "std", derive(Hash))]
#[derive(Encode)]
pub struct BoundedSlice<'a, T, S>(pub(super) &'a [T], PhantomData<S>);

Expand Down Expand Up @@ -273,6 +272,15 @@ impl<'a, T, S> Deref for BoundedSlice<'a, T, S> {
}
}

// Custom implementation of `Hash` since deriving it would require all generic bounds to also
// implement it.
#[cfg(feature = "std")]
impl<'a, T: std::hash::Hash, S> std::hash::Hash for BoundedSlice<'a, T, S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}

impl<'a, T, S> core::iter::IntoIterator for BoundedSlice<'a, T, S> {
type Item = &'a T;
type IntoIter = core::slice::Iter<'a, T>;
Expand Down Expand Up @@ -703,6 +711,15 @@ impl<T, S: Get<u32>> TruncateFrom<Vec<T>> for BoundedVec<T, S> {
}
}

// Custom implementation of `Hash` since deriving it would require all generic bounds to also
// implement it.
#[cfg(feature = "std")]
impl<T: std::hash::Hash, S> std::hash::Hash for BoundedVec<T, S> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}

// It is okay to give a non-mutable reference of the inner vec to anyone.
impl<T, S> AsRef<Vec<T>> for BoundedVec<T, S> {
fn as_ref(&self) -> &Vec<T> {
Expand Down Expand Up @@ -907,7 +924,7 @@ where
#[cfg(all(test, feature = "std"))]
mod test {
use super::*;
use crate::{bounded_vec, ConstU32};
use crate::{bounded_vec, ConstU32, ConstU8};
use codec::CompactLen;

#[test]
Expand Down Expand Up @@ -1289,4 +1306,17 @@ mod test {
assert_eq!(bound, &unbound[..]);
assert!(bound == &unbound[..]);
}

// Just a test that structs containing `BoundedVec` and `BoundedSlice` can derive `Hash`. (This was broken when
// they were deriving `Hash`).
#[test]
#[cfg(feature = "std")]
fn container_can_derive_hash() {
#[derive(Hash)]
struct Foo<'a> {
bar: u8,
slice: BoundedSlice<'a, usize, ConstU8<8>>,
map: BoundedVec<String, ConstU32<16>>,
}
}
}