Clarifying the Target: rand_distr 0.5.1 ≡ rand 0.9.x
Targeting the current ecosystem pairing: rand = "0.9" + rand_distr = "0.5.1" (released January 2025). These two crates form a coupled release: rand_distr 0.5 requires rand 0.9 and they must move together. smartcore currently sits on rand = "0.8.5" + rand_distr = "0.4" + getrandom = "0.2.8".[^1][^2][^3]
The Three-Crate Alignment Problem
This is the core challenge. rand 0.9 internally requires getrandom 0.3. Since smartcore directly depends on getrandom for its WASM path, the three crates must all be bumped atomically — you cannot upgrade rand without also upgrading getrandom, or the dependency resolver will pull conflicting versions into the tree:[^4]
| Crate |
Current |
Target |
Coupled constraint |
rand |
0.8.5 |
0.9.x |
requires getrandom 0.3 internally |
rand_distr |
0.4 |
0.5.1 |
requires rand 0.9 |
getrandom (wasm32) |
0.2.8 |
0.3.x |
feature rename: js → wasm_js [^5] |
Flag-by-Flag Breakdown
Smartcore has three distinct random code paths, each with different exposure to breaking changes:[^1]
Flag 1: Default (no extra flags) — SmallRng path
Uses SmallRng from rand with a fixed fallback seed of 0 on no-std / non-wasm targets. Risk: Low. SmallRng still exists in rand 0.9, and the small_rng feature is now enabled by default in rand 0.9. Since smartcore sets default-features = false, the feature must remain explicit — but the name is unchanged.[^6]
# No change needed beyond the version bump
rand = { version = "0.9", default-features = false, features = ["small_rng"] }
Flag 2: stdrand — StdRng + thread_rng() path
This flag activates StdRng and seeds it via rand::thread_rng().next_u64(). There are two changes here:[^6]
thread_rng() → renamed to rng() (old name deprecated, not removed yet)
- In rand 0.9 with
default-features = false, the thread_rng feature is now a separate explicit feature that must be pulled in[^6]
src/rand_custom.rs surgical change:
// Before (rand 0.8)
RngImpl::seed_from_u64(rand::thread_rng().next_u64())
// After (rand 0.9)
RngImpl::seed_from_u64(rand::rng().next_u64())
Cargo.toml stdrand feature update:
# Before
stdrand = ["rand/std_rng", "rand/std"]
# After — thread_rng is now its own feature in 0.9
stdrand = ["rand/std_rng", "rand/std", "rand/thread_rng"]
Flag 3: js — WebAssembly in-browser path
This is the most critical and breaking change in the entire upgrade. getrandom 0.3 removed the js crate feature entirely and replaced it with wasm_js. The current smartcore feature definition:[^5][^7]
# Current (getrandom 0.2.8)
js = ["getrandom/js"]
# Required (getrandom 0.3)
js = ["getrandom/wasm_js"]
This is a public API surface change — any downstream user who enables the js feature in their own Cargo.toml to target wasm32-unknown-unknown will get a compile error at the getrandom/js feature reference if smartcore is partially migrated. The rename must be complete and documented in release notes.[^8][^9]
Additional API-Level Changes
Beyond the random harness flags themselves, rand 0.9 introduces deprecation-level renames that won't break compilation immediately but will generate warnings and will need cleanup:[^6]
gen_range → random_range — used in src/ensemble/base_forest_regressor.rs:
// Deprecated in 0.9, still compiles:
let xi = rng.gen_range(0..nrows);
// Clean replacement:
let xi = rng.random_range(0..nrows);
rand::distributions module → rand::distr — if referenced anywhere directly:[^6]
// Deprecated import path
use rand::distributions::Distribution;
// Replacement
use rand::distr::Distribution;
SliceRandom trait split — rand 0.9 splits SliceRandom into IndexedRandom (for choose) and SliceRandom (for shuffle). src/model_selection/mod.rs imports SliceRandom; if it calls choose, an additional import of IndexedRandom is needed.[^1][^6]
rand_distr renamed types — if smartcore's dataset generators use WeightedAliasIndex or DistString, those paths moved:[^6]
weighted_alias::WeightedAliasIndex → weighted::WeightedAliasIndex
- Trait
DistString → SampleString
Complete Cargo.toml Diff
# [dependencies]
- rand = { version = "0.8.5", default-features = false, features = ["small_rng"] }
+ rand = { version = "0.9", default-features = false, features = ["small_rng"] }
- rand_distr = { version = "0.4", optional = true }
+ rand_distr = { version = "0.5", optional = true }
# [target.'cfg(target_arch = "wasm32")'.dependencies]
- getrandom = { version = "0.2.8", optional = true }
+ getrandom = { version = "0.3", optional = true }
# [features]
- js = ["getrandom/js"]
+ js = ["getrandom/wasm_js"]
- stdrand = ["rand/std_rng", "rand/std"]
+ stdrand = ["rand/std_rng", "rand/std", "rand/thread_rng"]
Viability Verdict
The upgrade is viable with low-to-medium effort. The code changes are localized and surgical — primarily in src/rand_custom.rs (one line) and Cargo.toml (four lines). The biggest risk isn't compilation; it's the getrandom js → wasm_js rename breaking WASM users downstream silently, and ensuring the WASM CI target (wasm32-unknown-unknown) is exercised in the test suite to validate the js feature path end-to-end after the rename. The wasm-bindgen-test harness already in dev-dependencies provides that coverage.[^8][^1]
Clarifying the Target:
rand_distr 0.5.1≡rand 0.9.xTargeting the current ecosystem pairing:
rand = "0.9"+rand_distr = "0.5.1"(released January 2025). These two crates form a coupled release:rand_distr 0.5requiresrand 0.9and they must move together. smartcore currently sits onrand = "0.8.5"+rand_distr = "0.4"+getrandom = "0.2.8".[^1][^2][^3]The Three-Crate Alignment Problem
This is the core challenge.
rand 0.9internally requiresgetrandom 0.3. Since smartcore directly depends ongetrandomfor its WASM path, the three crates must all be bumped atomically — you cannot upgrade rand without also upgrading getrandom, or the dependency resolver will pull conflicting versions into the tree:[^4]rand0.8.50.9.xgetrandom 0.3internallyrand_distr0.40.5.1rand 0.9getrandom(wasm32)0.2.80.3.xjs→wasm_js[^5]Flag-by-Flag Breakdown
Smartcore has three distinct random code paths, each with different exposure to breaking changes:[^1]
Flag 1: Default (no extra flags) —
SmallRngpathUses
SmallRngfrom rand with a fixed fallback seed of0on no-std / non-wasm targets. Risk: Low.SmallRngstill exists in rand 0.9, and thesmall_rngfeature is now enabled by default in rand 0.9. Since smartcore setsdefault-features = false, the feature must remain explicit — but the name is unchanged.[^6]Flag 2:
stdrand—StdRng+thread_rng()pathThis flag activates
StdRngand seeds it viarand::thread_rng().next_u64(). There are two changes here:[^6]thread_rng()→ renamed torng()(old name deprecated, not removed yet)default-features = false, thethread_rngfeature is now a separate explicit feature that must be pulled in[^6]src/rand_custom.rssurgical change:Cargo.tomlstdrandfeature update:Flag 3:
js— WebAssembly in-browser pathThis is the most critical and breaking change in the entire upgrade.
getrandom 0.3removed thejscrate feature entirely and replaced it withwasm_js. The current smartcore feature definition:[^5][^7]This is a public API surface change — any downstream user who enables the
jsfeature in their ownCargo.tomlto targetwasm32-unknown-unknownwill get a compile error at thegetrandom/jsfeature reference if smartcore is partially migrated. The rename must be complete and documented in release notes.[^8][^9]Additional API-Level Changes
Beyond the random harness flags themselves, rand 0.9 introduces deprecation-level renames that won't break compilation immediately but will generate warnings and will need cleanup:[^6]
gen_range→random_range— used insrc/ensemble/base_forest_regressor.rs:rand::distributionsmodule →rand::distr— if referenced anywhere directly:[^6]SliceRandomtrait split — rand 0.9 splitsSliceRandomintoIndexedRandom(forchoose) andSliceRandom(forshuffle).src/model_selection/mod.rsimportsSliceRandom; if it callschoose, an additional import ofIndexedRandomis needed.[^1][^6]rand_distrrenamed types — if smartcore's dataset generators useWeightedAliasIndexorDistString, those paths moved:[^6]weighted_alias::WeightedAliasIndex→weighted::WeightedAliasIndexDistString→SampleStringComplete Cargo.toml Diff
Viability Verdict
The upgrade is viable with low-to-medium effort. The code changes are localized and surgical — primarily in
src/rand_custom.rs(one line) andCargo.toml(four lines). The biggest risk isn't compilation; it's thegetrandom js → wasm_jsrename breaking WASM users downstream silently, and ensuring the WASM CI target (wasm32-unknown-unknown) is exercised in the test suite to validate thejsfeature path end-to-end after the rename. Thewasm-bindgen-testharness already indev-dependenciesprovides that coverage.[^8][^1]