Skip to content

Commit

Permalink
Improve serialization support
Browse files Browse the repository at this point in the history
  • Loading branch information
pczarn committed Dec 1, 2024
2 parents abd75bb + 434d049 commit a120c10
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 28 deletions.
10 changes: 10 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ jobs:
run: cargo test --no-default-features --verbose
- name: Run tests for serde
run: cargo test --features serde --verbose
- run: cargo test --no-default-features --features serde_no_std
- run: cargo test --features borsh
- run: cargo test --features miniserde
- run: cargo test --features nanoserde
- run: cargo test --features nanoserde --no-default-features

miri:
name: "Miri"
Expand Down Expand Up @@ -62,7 +67,12 @@ jobs:
- run: cargo build
- run: cargo test
- run: cargo test --no-default-features
- run: cargo test --no-default-features --features serde_no_std
- run: cargo test --features serde
- run: cargo test --features borsh
- run: cargo test --features miniserde
- run: cargo test --features nanoserde
- run: cargo test --features nanoserde --no-default-features

clippy:
runs-on: ubuntu-latest
Expand Down
16 changes: 15 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ edition = "2021"
rust-version = "1.63"

[dependencies]
serde = { version = "1.0", features = ["derive"], optional = true }
borsh = { version = "1.5", default-features = false, features = ["derive"], optional = true }
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
miniserde = { version = "0.1", optional = true }
nanoserde = { version = "0.1", optional = true }

[dependencies.bit-vec]
version = "0.8.0"
Expand All @@ -26,4 +29,15 @@ serde_json = "1.0"
[features]
default = ["std"]
std = ["bit-vec/std"]

borsh = ["dep:borsh", "bit-vec/borsh"]
serde = ["dep:serde", "bit-vec/serde"]
miniserde = ["dep:miniserde", "bit-vec/miniserde"]
nanoserde = ["dep:nanoserde", "bit-vec/nanoserde"]

serde_std = ["std", "serde/std"]
serde_no_std = ["serde/alloc"]
borsh_std = ["borsh/std"]

[package.metadata.docs.rs]
features = ["borsh", "serde", "miniserde", "nanoserde"]
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@ If you want to use bit-set in a program that has `#![no_std]`, just drop default
bit-set = { version = "0.8", default-features = false }
```

If you want to use serde with the alloc crate instead of std, just use the `serde_no_std` feature:

```toml
[dependencies]
bit-set = { version = "0.8", default-features = false, features = ["serde", "serde_no_std"] }
```

If you want [borsh-rs](https://github.com/near/borsh-rs) support, include it like this:

```toml
[dependencies]
bit-set = { version = "0.8", features = ["borsh"] }
```

Other available serialization libraries can be enabled with the
[`miniserde`](https://github.com/dtolnay/miniserde) and
[`nanoserde`](https://github.com/not-fl3/nanoserde) features.


<!-- cargo-rdme start -->

### Description
Expand Down
131 changes: 104 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ use core::fmt;
use core::hash;
use core::iter::{self, Chain, Enumerate, FromIterator, Repeat, Skip, Take};

#[cfg(feature = "nanoserde")]
extern crate alloc;
#[cfg(feature = "nanoserde")]
use alloc::vec::Vec;
#[cfg(feature = "nanoserde")]
use nanoserde::{DeBin, DeJson, DeRon, SerBin, SerJson, SerRon};

type MatchWords<'a, B> = Chain<Enumerate<Blocks<'a, B>>, Skip<Take<Enumerate<Repeat<B>>>>>;

/// Computes how many blocks are needed to store that many bits
Expand Down Expand Up @@ -116,6 +123,18 @@ fn match_words<'a, 'b, B: BitBlock>(
}

#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
#[cfg_attr(
feature = "borsh",
derive(borsh::BorshDeserialize, borsh::BorshSerialize)
)]
#[cfg_attr(
feature = "miniserde",
derive(miniserde::Deserialize, miniserde::Serialize)
)]
#[cfg_attr(
feature = "nanoserde",
derive(DeBin, DeJson, DeRon, SerBin, SerJson, SerRon)
)]
pub struct BitSet<B = u32> {
bit_vec: BitVec<B>,
}
Expand Down Expand Up @@ -783,12 +802,23 @@ impl<B: BitBlock> BitSet<B> {
}
*/

/// Returns the number of set bits in this set.
/// Counts the number of set bits in this set.
///
/// Note that this function scans the set to calculate the number.
#[inline]
pub fn len(&self) -> usize {
pub fn count(&self) -> usize {
self.bit_vec.blocks().fold(0, |acc, n| acc + n.count_ones())
}

/// Counts the number of set bits in this set.
///
/// Note that this function scans the set to calculate the number.
#[inline]
#[deprecated = "use BitVec::count() instead"]
pub fn len(&self) -> usize {
self.count()
}

/// Returns whether there are no bits set in this set
#[inline]
pub fn is_empty(&self) -> bool {
Expand Down Expand Up @@ -1190,7 +1220,7 @@ mod tests {
assert!(b.insert(400));
assert!(!b.insert(400));
assert!(b.contains(400));
assert_eq!(b.len(), 3);
assert_eq!(b.count(), 3);
}

#[test]
Expand Down Expand Up @@ -1346,8 +1376,8 @@ mod tests {
let c = a.clone();
a.union_with(&b);
b.union_with(&c);
assert_eq!(a.len(), 4);
assert_eq!(b.len(), 4);
assert_eq!(a.count(), 4);
assert_eq!(b.count(), 4);
}

#[test]
Expand Down Expand Up @@ -1376,8 +1406,8 @@ mod tests {
let c = a.clone();
a.intersect_with(&b);
b.intersect_with(&c);
assert_eq!(a.len(), 2);
assert_eq!(b.len(), 2);
assert_eq!(a.count(), 2);
assert_eq!(b.count(), 2);
}

#[test]
Expand All @@ -1400,8 +1430,8 @@ mod tests {
let c = a.clone();
a.difference_with(&b);
b.difference_with(&c);
assert_eq!(a.len(), 1);
assert_eq!(b.len(), 1);
assert_eq!(a.count(), 1);
assert_eq!(b.count(), 1);
}

#[test]
Expand Down Expand Up @@ -1429,8 +1459,8 @@ mod tests {
let c = a.clone();
a.symmetric_difference_with(&b);
b.symmetric_difference_with(&c);
assert_eq!(a.len(), 2);
assert_eq!(b.len(), 2);
assert_eq!(a.count(), 2);
assert_eq!(b.count(), 2);
}

#[test]
Expand Down Expand Up @@ -1467,31 +1497,31 @@ mod tests {
// and this would end up actually growing the array in a way
// that (safely corrupted the state).
let mut a = BitSet::new();
assert_eq!(a.len(), 0);
assert_eq!(a.count(), 0);
assert_eq!(a.capacity(), 0);
a.shrink_to_fit();
assert_eq!(a.len(), 0);
assert_eq!(a.count(), 0);
assert_eq!(a.capacity(), 0);
assert!(!a.contains(1));
a.insert(3);
assert!(a.contains(3));
assert_eq!(a.len(), 1);
assert_eq!(a.count(), 1);
assert!(a.capacity() > 0);
a.shrink_to_fit();
assert!(a.contains(3));
assert_eq!(a.len(), 1);
assert_eq!(a.count(), 1);
assert!(a.capacity() > 0);
}

#[test]
fn test_bit_set_shrink_to_fit() {
let mut a = BitSet::new();
assert_eq!(a.len(), 0);
assert_eq!(a.count(), 0);
assert_eq!(a.capacity(), 0);
a.insert(259);
a.insert(98);
a.insert(3);
assert_eq!(a.len(), 3);
assert_eq!(a.count(), 3);
assert!(a.capacity() > 0);
assert!(!a.contains(1));
assert!(a.contains(259));
Expand All @@ -1503,7 +1533,7 @@ mod tests {
assert!(a.contains(259));
assert!(a.contains(98));
assert!(a.contains(3));
assert_eq!(a.len(), 3);
assert_eq!(a.count(), 3);
assert!(a.capacity() > 0);

let old_cap = a.capacity();
Expand All @@ -1514,20 +1544,20 @@ mod tests {
assert!(!a.contains(259));
assert!(a.contains(98));
assert!(a.contains(3));
assert_eq!(a.len(), 2);
assert_eq!(a.count(), 2);

let old_cap2 = a.capacity();
a.clear();
assert_eq!(a.capacity(), old_cap2);
assert_eq!(a.len(), 0);
assert_eq!(a.count(), 0);
assert!(!a.contains(1));
assert!(!a.contains(259));
assert!(!a.contains(98));
assert!(!a.contains(3));

a.insert(512);
assert!(a.capacity() > 0);
assert_eq!(a.len(), 1);
assert_eq!(a.count(), 1);
assert!(a.contains(512));
assert!(!a.contains(1));
assert!(!a.contains(259));
Expand All @@ -1537,7 +1567,7 @@ mod tests {
a.remove(512);
a.shrink_to_fit();
assert_eq!(a.capacity(), 0);
assert_eq!(a.len(), 0);
assert_eq!(a.count(), 0);
assert!(!a.contains(512));
assert!(!a.contains(1));
assert!(!a.contains(259));
Expand Down Expand Up @@ -1588,20 +1618,20 @@ mod tests {
s.truncate(5 * 8);

assert_eq!(s, BitSet::from_bytes(&bytes[..5]));
assert_eq!(s.len(), 5 * 8);
assert_eq!(s.count(), 5 * 8);
s.truncate(4 * 8);
assert_eq!(s, BitSet::from_bytes(&bytes[..4]));
assert_eq!(s.len(), 4 * 8);
assert_eq!(s.count(), 4 * 8);
// Truncating to a size > s.len() should be a noop
s.truncate(5 * 8);
assert_eq!(s, BitSet::from_bytes(&bytes[..4]));
assert_eq!(s.len(), 4 * 8);
assert_eq!(s.count(), 4 * 8);
s.truncate(8);
assert_eq!(s, BitSet::from_bytes(&bytes[..1]));
assert_eq!(s.len(), 8);
assert_eq!(s.count(), 8);
s.truncate(0);
assert_eq!(s, BitSet::from_bytes(&[]));
assert_eq!(s.len(), 0);
assert_eq!(s.count(), 0);
}

#[cfg(feature = "serde")]
Expand All @@ -1619,6 +1649,53 @@ mod tests {
assert_eq!(bset, unserialized);
}

#[cfg(feature = "miniserde")]
#[test]
fn test_miniserde_serialization() {
let bset: BitSet = BitSet::new();
let serialized = miniserde::json::to_string(&bset);
let unserialized: BitSet = miniserde::json::from_str(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);

let elems: Vec<usize> = vec![11, 42, 100, 101];
let bset: BitSet = elems.iter().map(|n| *n).collect();
let serialized = miniserde::json::to_string(&bset);
let unserialized = miniserde::json::from_str(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);
}

#[cfg(feature = "nanoserde")]
#[test]
fn test_nanoserde_json_serialization() {
use nanoserde::{DeJson, SerJson};

let bset: BitSet = BitSet::new();
let serialized = bset.serialize_json();
let unserialized: BitSet = BitSet::deserialize_json(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);

let elems: Vec<usize> = vec![11, 42, 100, 101];
let bset: BitSet = elems.iter().map(|n| *n).collect();
let serialized = bset.serialize_json();
let unserialized = BitSet::deserialize_json(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);
}

#[cfg(feature = "borsh")]
#[test]
fn test_borsh_serialization() {
let bset: BitSet = BitSet::new();
let serialized = borsh::to_vec(&bset).unwrap();
let unserialized: BitSet = borsh::from_slice(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);

let elems: Vec<usize> = vec![11, 42, 100, 101];
let bset: BitSet = elems.iter().map(|n| *n).collect();
let serialized = borsh::to_vec(&bset).unwrap();
let unserialized = borsh::from_slice(&serialized[..]).unwrap();
assert_eq!(bset, unserialized);
}

/*
#[test]
fn test_bit_set_append() {
Expand Down

0 comments on commit a120c10

Please sign in to comment.