diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 87878f8..9f59c71 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,8 +52,10 @@ jobs: - uses: taiki-e/install-action@v2 with: tool: typos-cli,taplo-cli,hawkeye - - name: Check all + - name: Check linters run: cargo x lint + - name: Check feature matrix + run: cargo x check msrv: name: Resolve MSRV diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b71cab9..dff59fd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,7 +27,7 @@ Rustup will read the `rust-toolchain.toml` file and set up everything else autom ```shell cargo version -# cargo 1.85.0 ( 2024-12-31) +# cargo 1.86.0 ( ) ``` To keep code style consistent, run `cargo x lint --fix` to automatically fix any style issues before committing your changes. diff --git a/Cargo.lock b/Cargo.lock index 3f3c50a..f3212f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -79,6 +79,38 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +[[package]] +name = "camino" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +dependencies = [ + "serde_core", +] + +[[package]] +name = "cargo-platform" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122ec45a44b270afd1402f351b782c676b173e3c3fb28d86ff7ebfb4d86a4ee4" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef987d17b0a113becdd19d3d0022d04d7ef41f9efe4f3fb63ac44ba61df3ade9" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -231,9 +263,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.17.0" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -254,7 +286,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", - "hashbrown 0.17.0", + "hashbrown 0.17.1", "serde", "serde_core", ] @@ -421,6 +453,10 @@ name = "semver" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +dependencies = [ + "serde", + "serde_core", +] [[package]] name = "serde" @@ -429,6 +465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", + "serde_derive", ] [[package]] @@ -500,6 +537,26 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-ident" version = "1.0.24" @@ -692,6 +749,7 @@ dependencies = [ name = "x" version = "0.0.0" dependencies = [ + "cargo_metadata", "clap", "which", ] diff --git a/Cargo.toml b/Cargo.toml index 38d8511..82d7702 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ homepage = "https://datasketches.apache.org" license = "Apache-2.0" readme = "README.md" repository = "https://github.com/apache/datasketches-rust" -rust-version = "1.85.0" +rust-version = "1.86.0" [workspace.dependencies] # Workspace dependencies @@ -35,7 +35,7 @@ datasketches = { path = "datasketches" } clap = { version = "4.5.20", features = ["derive"] } insta = { version = "1.46.1" } googletest = { version = "0.14.2" } -rand = { version = "0.9.2" } +cargo_metadata = { version = "0.23.1" } which = { version = "8.0.0" } [workspace.lints.rust] diff --git a/README.md b/README.md index bc1eabe..ad6d3b1 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ [![Crates.io][crates-badge]][crates-url] [![Documentation][docs-badge]][docs-url] -[![MSRV 1.85.0][msrv-badge]](https://www.whatrustisit.com) +[![MSRV 1.86.0][msrv-badge]](https://www.whatrustisit.com) [![Apache 2.0 licensed][license-badge]][license-url] [![Build Status][actions-badge]][actions-url] @@ -29,7 +29,7 @@ [crates-url]: https://crates.io/crates/datasketches [docs-badge]: https://img.shields.io/docsrs/datasketches [docs-url]: https://docs.rs/datasketches -[msrv-badge]: https://img.shields.io/badge/MSRV-1.85.0-green?logo=rust +[msrv-badge]: https://img.shields.io/badge/MSRV-1.86.0-green?logo=rust [license-badge]: https://img.shields.io/crates/l/datasketches [license-url]: LICENSE [actions-badge]: https://github.com/apache/datasketches-rust/workflows/CI/badge.svg diff --git a/datasketches/Cargo.toml b/datasketches/Cargo.toml index 214288e..696fe39 100644 --- a/datasketches/Cargo.toml +++ b/datasketches/Cargo.toml @@ -34,6 +34,18 @@ keywords = ["sketch", "hyperloglog", "probabilistic"] all-features = true rustdoc-args = ["--cfg", "docsrs"] +[features] +default = [] + +# Each sketch has its own feature, so that users can opt in to only the sketches they need. +bloom = [] +countmin = [] +cpc = [] +frequencies = [] +hll = [] +tdigest = [] +theta = [] + [dev-dependencies] googletest = { workspace = true } insta = { workspace = true } diff --git a/datasketches/src/codec/family.rs b/datasketches/src/codec/family.rs index 21cf2b4..cc1ce45 100644 --- a/datasketches/src/codec/family.rs +++ b/datasketches/src/codec/family.rs @@ -27,13 +27,16 @@ pub struct Family { /// The name for this family. pub name: &'static str, /// The minimum preamble size for this family in longs (8-bytes integer). + #[allow(dead_code)] // only some sketches need to check this field pub min_pre_longs: u8, /// The maximum preamble size for this family in longs (8-bytes integer). + #[allow(dead_code)] // only some sketches need to check this field pub max_pre_longs: u8, } impl Family { /// Theta Sketch for cardinality estimation. + #[cfg(feature = "theta")] pub const THETA: Family = Family { id: 3, name: "THETA", @@ -42,6 +45,7 @@ impl Family { }; /// The HLL family of sketches. + #[cfg(feature = "hll")] pub const HLL: Family = Family { id: 7, name: "HLL", @@ -50,6 +54,7 @@ impl Family { }; /// The Frequency family of sketches. + #[cfg(feature = "frequencies")] pub const FREQUENCY: Family = Family { id: 10, name: "FREQUENCY", @@ -58,6 +63,7 @@ impl Family { }; /// Compressed Probabilistic Counting (CPC) Sketch. + #[cfg(feature = "cpc")] pub const CPC: Family = Family { id: 16, name: "CPC", @@ -66,6 +72,7 @@ impl Family { }; /// CountMin Sketch + #[cfg(feature = "countmin")] pub const COUNTMIN: Family = Family { id: 18, name: "COUNTMIN", @@ -74,6 +81,7 @@ impl Family { }; /// T-Digest for estimating quantiles and ranks. + #[cfg(feature = "tdigest")] pub const TDIGEST: Family = Family { id: 20, name: "TDIGEST", @@ -82,6 +90,7 @@ impl Family { }; /// Bloom Filter. + #[cfg(feature = "bloom")] pub const BLOOMFILTER: Family = Family { id: 21, name: "BLOOMFILTER", diff --git a/datasketches/src/codec/mod.rs b/datasketches/src/codec/mod.rs index 28008ff..5b78f53 100644 --- a/datasketches/src/codec/mod.rs +++ b/datasketches/src/codec/mod.rs @@ -17,12 +17,30 @@ //! Codec utilities for datasketches crate. -// public common codec utilities for datasketches crate mod decode; mod encode; pub use self::decode::SketchSlice; pub use self::encode::SketchBytes; -// private to datasketches crate +#[cfg(any( + feature = "bloom", + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "tdigest", + feature = "theta" +))] +#[allow(dead_code)] // some utilities are only used for certain sketches pub(crate) mod assert; + +#[cfg(any( + feature = "bloom", + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "tdigest", + feature = "theta" +))] pub(crate) mod family; diff --git a/datasketches/src/common/mod.rs b/datasketches/src/common/mod.rs index 36b734f..503df72 100644 --- a/datasketches/src/common/mod.rs +++ b/datasketches/src/common/mod.rs @@ -17,12 +17,12 @@ //! Data structures and functions that may be used across all the sketch families. -// public common components for datasketches crate mod num_std_dev; mod resize; pub use self::num_std_dev::NumStdDev; pub use self::resize::ResizeFactor; -// private to datasketches crate +#[cfg(feature = "theta")] pub(crate) mod binomial_bounds; +#[cfg(feature = "cpc")] pub(crate) mod inv_pow2_table; diff --git a/datasketches/src/error.rs b/datasketches/src/error.rs index ee282aa..8ec5c10 100644 --- a/datasketches/src/error.rs +++ b/datasketches/src/error.rs @@ -89,7 +89,8 @@ impl Error { } } -// Convenient constructors used within datasketches crate. +// pub(crate) convenient constructors +#[allow(dead_code)] // some constructors are only used for certain sketches impl Error { pub(crate) fn invalid_argument(msg: impl Into) -> Self { Self::new(ErrorKind::InvalidArgument, msg) diff --git a/datasketches/src/hash/mod.rs b/datasketches/src/hash/mod.rs index 99d2cca..0a77759 100644 --- a/datasketches/src/hash/mod.rs +++ b/datasketches/src/hash/mod.rs @@ -15,10 +15,26 @@ // specific language governing permissions and limitations // under the License. +#[cfg(any( + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "theta" +))] mod murmurhash; -mod xxhash; - +#[cfg(any( + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "theta" +))] pub(crate) use self::murmurhash::MurmurHash3X64128; + +#[cfg(feature = "bloom")] +mod xxhash; +#[cfg(feature = "bloom")] pub(crate) use self::xxhash::XxHash64; /// The seed 9001 used in the sketch update methods is a prime number that was chosen very early @@ -34,6 +50,14 @@ pub(crate) use self::xxhash::XxHash64; /// and seed are identical for both sketches, otherwise the assumed 1:1 relationship between the /// original source key value and the hashed bit string would be violated. Once you have developed /// a history of stored sketches you are stuck with it. +#[cfg(any( + feature = "bloom", + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "theta" +))] pub(crate) const DEFAULT_UPDATE_SEED: u64 = 9001; /// Computes and checks the 16-bit seed hash from the given long seed. @@ -44,6 +68,7 @@ pub(crate) const DEFAULT_UPDATE_SEED: u64 = 9001; /// # Panics /// /// Panics if the computed seed hash is zero. +#[cfg(any(feature = "countmin", feature = "cpc", feature = "theta"))] pub(crate) fn compute_seed_hash(seed: u64) -> u16 { use std::hash::Hasher; @@ -60,6 +85,14 @@ pub(crate) fn compute_seed_hash(seed: u64) -> u16 { /// # Panics /// /// Panics if `bytes.len()` is greater than 8. +#[cfg(any( + feature = "bloom", + feature = "countmin", + feature = "cpc", + feature = "frequencies", + feature = "hll", + feature = "theta" +))] fn read_u64_le(bytes: &[u8]) -> u64 { let mut buf = [0u8; 8]; buf[..bytes.len()].copy_from_slice(bytes); diff --git a/datasketches/src/lib.rs b/datasketches/src/lib.rs index 33ea2f8..65f0ddd 100644 --- a/datasketches/src/lib.rs +++ b/datasketches/src/lib.rs @@ -30,16 +30,27 @@ #[cfg(target_endian = "big")] compile_error!("datasketches does not support big-endian targets"); +// sketches modules +#[cfg(feature = "bloom")] pub mod bloom; -pub mod codec; -pub mod common; +#[cfg(feature = "countmin")] pub mod countmin; +#[cfg(feature = "cpc")] pub mod cpc; -pub mod error; +#[cfg(feature = "frequencies")] pub mod frequencies; -pub mod hash_value; +#[cfg(feature = "hll")] pub mod hll; +#[cfg(feature = "tdigest")] pub mod tdigest; +#[cfg(feature = "theta")] pub mod theta; +// common modules +pub mod codec; +pub mod common; +pub mod error; +pub mod hash_value; + +// private internal modules mod hash; diff --git a/datasketches/tests/bloom_serialization_test.rs b/datasketches/tests/bloom_serialization_test.rs index 15daba2..f096679 100644 --- a/datasketches/tests/bloom_serialization_test.rs +++ b/datasketches/tests/bloom_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "bloom")] + mod common; use std::fs; diff --git a/datasketches/tests/countmin_test.rs b/datasketches/tests/countmin_test.rs index dddc72c..a8681e4 100644 --- a/datasketches/tests/countmin_test.rs +++ b/datasketches/tests/countmin_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "countmin")] + use datasketches::countmin::CountMinSketch; #[test] diff --git a/datasketches/tests/cpc_serialization_test.rs b/datasketches/tests/cpc_serialization_test.rs index bbcb56e..85b749a 100644 --- a/datasketches/tests/cpc_serialization_test.rs +++ b/datasketches/tests/cpc_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "cpc")] + mod common; use std::fs; diff --git a/datasketches/tests/cpc_union_test.rs b/datasketches/tests/cpc_union_test.rs index 36badbd..5bc3b18 100644 --- a/datasketches/tests/cpc_union_test.rs +++ b/datasketches/tests/cpc_union_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "cpc")] + use datasketches::cpc::CpcSketch; use datasketches::cpc::CpcUnion; use googletest::assert_that; diff --git a/datasketches/tests/cpc_update_test.rs b/datasketches/tests/cpc_update_test.rs index 7b814f7..8e78995 100644 --- a/datasketches/tests/cpc_update_test.rs +++ b/datasketches/tests/cpc_update_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "cpc")] + use datasketches::common::NumStdDev; use datasketches::cpc::CpcSketch; use googletest::assert_that; diff --git a/datasketches/tests/cpc_wrapper_test.rs b/datasketches/tests/cpc_wrapper_test.rs index 6355ed0..4545e20 100644 --- a/datasketches/tests/cpc_wrapper_test.rs +++ b/datasketches/tests/cpc_wrapper_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "cpc")] + use datasketches::common::NumStdDev; use datasketches::cpc::CpcSketch; use datasketches::cpc::CpcUnion; diff --git a/datasketches/tests/frequencies_serialization_test.rs b/datasketches/tests/frequencies_serialization_test.rs index f8d95bc..fd82761 100644 --- a/datasketches/tests/frequencies_serialization_test.rs +++ b/datasketches/tests/frequencies_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "frequencies")] + mod common; use std::fs; diff --git a/datasketches/tests/frequencies_update_test.rs b/datasketches/tests/frequencies_update_test.rs index a5a98e1..f15f219 100644 --- a/datasketches/tests/frequencies_update_test.rs +++ b/datasketches/tests/frequencies_update_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "frequencies")] + use datasketches::frequencies::ErrorType; use datasketches::frequencies::FrequentItemsSketch; diff --git a/datasketches/tests/hll_serialization_test.rs b/datasketches/tests/hll_serialization_test.rs index 4f7291b..c3f9d97 100644 --- a/datasketches/tests/hll_serialization_test.rs +++ b/datasketches/tests/hll_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "hll")] + mod common; use std::fs; diff --git a/datasketches/tests/hll_union_test.rs b/datasketches/tests/hll_union_test.rs index 91080bf..5bc3bb8 100644 --- a/datasketches/tests/hll_union_test.rs +++ b/datasketches/tests/hll_union_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "hll")] + //! HyperLogLog Union Integration Tests //! //! These tests verify the public API behavior of HllUnion, focusing on: diff --git a/datasketches/tests/hll_update_test.rs b/datasketches/tests/hll_update_test.rs index e72c6fc..0b0d611 100644 --- a/datasketches/tests/hll_update_test.rs +++ b/datasketches/tests/hll_update_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "hll")] + use datasketches::common::NumStdDev; use datasketches::hll::HllSketch; use datasketches::hll::HllType; diff --git a/datasketches/tests/tdigest_serialization_test.rs b/datasketches/tests/tdigest_serialization_test.rs index 18f58ce..d52983e 100644 --- a/datasketches/tests/tdigest_serialization_test.rs +++ b/datasketches/tests/tdigest_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "tdigest")] + mod common; use std::fs; diff --git a/datasketches/tests/tdigest_test.rs b/datasketches/tests/tdigest_test.rs index b61d779..cce2130 100644 --- a/datasketches/tests/tdigest_test.rs +++ b/datasketches/tests/tdigest_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "tdigest")] + use datasketches::tdigest::TDigestMut; use googletest::assert_that; use googletest::prelude::eq; diff --git a/datasketches/tests/theta_intersection_test.rs b/datasketches/tests/theta_intersection_test.rs index 4959529..9b98062 100644 --- a/datasketches/tests/theta_intersection_test.rs +++ b/datasketches/tests/theta_intersection_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "theta")] + use datasketches::theta::CompactThetaSketch; use datasketches::theta::ThetaIntersection; use datasketches::theta::ThetaSketch; diff --git a/datasketches/tests/theta_serialization_test.rs b/datasketches/tests/theta_serialization_test.rs index fd07d51..48c1c12 100644 --- a/datasketches/tests/theta_serialization_test.rs +++ b/datasketches/tests/theta_serialization_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "theta")] + mod common; use std::fs; diff --git a/datasketches/tests/theta_sketch_test.rs b/datasketches/tests/theta_sketch_test.rs index 28448c2..55664ef 100644 --- a/datasketches/tests/theta_sketch_test.rs +++ b/datasketches/tests/theta_sketch_test.rs @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#![cfg(feature = "theta")] + use datasketches::common::NumStdDev; use datasketches::hash_value; use datasketches::theta::ThetaSketch; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index a260d8d..7df2ea3 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -16,5 +16,5 @@ # under the License. [toolchain] -channel = "1.85.0" +channel = "1.86.0" components = ["rustfmt", "clippy", "rust-analyzer"] diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml index 5b04167..080aa8a 100644 --- a/xtask/Cargo.toml +++ b/xtask/Cargo.toml @@ -31,6 +31,7 @@ release = false [dependencies] clap = { workspace = true } +cargo_metadata = { workspace = true } which = { workspace = true } [lints] diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 6af7f65..260f426 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +use std::path::Path; use std::process::Command as StdCommand; use clap::Parser; @@ -29,6 +30,7 @@ struct Command { impl Command { fn run(self) { match self.sub { + SubCommand::Check(cmd) => cmd.run(), SubCommand::Lint(cmd) => cmd.run(), SubCommand::Test(cmd) => cmd.run(), } @@ -37,12 +39,30 @@ impl Command { #[derive(Subcommand)] enum SubCommand { + #[clap(about = "Check datasketches under the feature matrix.")] + Check(CommandCheck), #[clap(about = "Run format and clippy checks.")] Lint(CommandLint), #[clap(about = "Run unit tests.")] Test(CommandTest), } +#[derive(Parser)] +#[clap(name = "check")] +struct CommandCheck {} + +impl CommandCheck { + fn run(self) { + let features = datasketches_features(); + + run_command(make_check_cmd(&[])); + for feature in features.chunks(1) { + run_command(make_check_cmd(feature)); + } + run_command(make_check_cmd(&features)); + } +} + #[derive(Parser)] struct CommandTest { #[arg(long, help = "Run tests serially and do not capture output.")] @@ -51,10 +71,36 @@ struct CommandTest { impl CommandTest { fn run(self) { - run_command(make_test_cmd(self.no_capture, &[])); + let features = datasketches_features(); + run_command(make_test_cmd(self.no_capture, &features)); } } +fn datasketches_features() -> Vec { + use cargo_metadata::Metadata; + use cargo_metadata::MetadataCommand; + + let datasketches_manifest = Path::new(env!("CARGO_WORKSPACE_DIR")).join("Cargo.toml"); + + let Metadata { packages, .. } = MetadataCommand::new() + .manifest_path(datasketches_manifest) + .exec() + .expect("failed to get cargo metadata"); + + let pkg = packages + .into_iter() + .find(|p| p.name == "datasketches") + .expect("failed to find datasketches package"); + + let mut features = pkg + .features + .into_keys() + .filter(|feature| feature != "default") + .collect::>(); + features.sort(); + features +} + #[derive(Parser)] #[clap(name = "lint")] struct CommandLint { @@ -100,11 +146,11 @@ fn run_command(mut cmd: StdCommand) { assert!(status.success(), "command failed: {status}"); } -fn make_test_cmd(no_capture: bool, features: &[&str]) -> StdCommand { +fn make_test_cmd(no_capture: bool, features: &[String]) -> StdCommand { let mut cmd = find_command("cargo"); cmd.args(["test", "--workspace", "--no-default-features"]); - if !features.is_empty() { - cmd.args(["--features", features.join(",").as_str()]); + for feature in features { + cmd.args(["--features", feature]); } if no_capture { cmd.args(["--", "--nocapture"]); @@ -112,6 +158,23 @@ fn make_test_cmd(no_capture: bool, features: &[&str]) -> StdCommand { cmd } +fn make_check_cmd(features: &[String]) -> StdCommand { + let mut cmd = find_command("cargo"); + cmd.env("RUSTFLAGS", "-Dwarnings"); + cmd.args([ + "+nightly", + "check", + "--package", + "datasketches", + "--all-targets", + "--no-default-features", + ]); + for feature in features { + cmd.args(["--features", feature]); + } + cmd +} + fn make_format_cmd(fix: bool) -> StdCommand { let mut cmd = find_command("cargo"); cmd.args(["+nightly", "fmt", "--all"]);