diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4254c4d..628ec96 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -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" @@ -62,7 +67,27 @@ 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 miniserde + + msrv-borsh: + name: Rust ${{matrix.rust}} + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + rust: [1.67.0, 1.68.0] + timeout-minutes: 45 + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{matrix.rust}} + - run: cargo test + - run: cargo test --features borsh + - run: cargo test --features nanoserde + - run: cargo test --features nanoserde --no-default-features clippy: runs-on: ubuntu-latest diff --git a/Cargo.toml b/Cargo.toml index b7bdd17..05fbd36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" @@ -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"] diff --git a/README.md b/README.md index 3fa4e26..d7e96a9 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ [![Documentation][docs.rs badge]][docs.rs link] ![Rust CI][github ci badge] ![rustc 1.63+] +![borsh: rustc 1.67+] +![nanoserde: rustc 1.67+]

[![Dependency Status][deps.rs status]][deps.rs link] @@ -23,6 +25,8 @@ [docs.rs link]: https://docs.rs/bit-set/0.8.0/bit_set/ [github ci badge]: https://github.com/contain-rs/bit-set/workflows/Rust/badge.svg?branch=master [rustc 1.63+]: https://img.shields.io/badge/rustc-1.63%2B-blue.svg +[borsh: rustc 1.67+]: https://img.shields.io/badge/borsh:%20rustc-1.67%2B-blue.svg +[nanoserde: rustc 1.67+]: https://img.shields.io/badge/nanoserde:%20rustc-1.67%2B-blue.svg [deps.rs status]: https://deps.rs/crate/bit-set/0.8.0/status.svg [deps.rs link]: https://deps.rs/crate/bit-set/0.8.0 [shields.io download count]: https://img.shields.io/crates/d/bit-set.svg @@ -57,6 +61,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. + + ### Description diff --git a/src/lib.rs b/src/lib.rs index 5bdf9a8..899b9dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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>, Skip>>>>; /// Computes how many blocks are needed to store that many bits @@ -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 { bit_vec: BitVec, } @@ -1599,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")] @@ -1630,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 = 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 = 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 = 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() {