Add the shuttle_enabler crate - #325
Open
sarsko wants to merge 3 commits into
Open
Conversation
wrappers/README.md has documented a `shuttle_enabler` crate since #240, but the crate was never added, so the instructions could not be followed and the `[shuttle_enabler](shuttle_enabler)` link was dead. This adds it. The problem it solves: a crate depending on several wrappers has to list every one of them in its own `shuttle` feature. That list is easy to get wrong, and getting it wrong is quiet -- a missing entry does not fail the build, it leaves that dependency running its real implementation inside a Shuttle test, where the scheduler has no control over it. Depending on shuttle_enabler reduces the list to one entry, and adding a wrapped dependency later needs no change to it. The crate contains no code. It owns a `shuttle` feature that enables the `shuttle` feature of all ten wrappers plus `determinizable_collections`' `deterministic` feature. Cargo compiles each crate once with the union of the features requested of it, so a downstream crate's own `shuttle-tokio` dependency picks up the feature without naming it. Details worth noting for review: * Every dependency is optional and activated only by the `shuttle` feature, so depending on this crate costs nothing when the feature is off. Verified: `cargo check -p shuttle_enabler` compiles no wrapper crates at all. * Dependencies use `default-features = false` so the crate contributes only the `shuttle` feature and does not silently turn on other features on a downstream crate's behalf. * Version requirements are as permissive as semver allows on purpose. The whole mechanism depends on Cargo unifying this crate's dependency on a wrapper with the downstream crate's own dependency on it. If they resolve to semver-incompatible versions, Cargo builds two copies and only this crate's copy gets the feature, so the downstream crate keeps using the real implementation and its Shuttle test passes without testing anything. This failure mode is documented in both READMEs rather than left as a trap. Verified the mechanism end to end with a scratch crate that depends on shuttle_enabler and on `tokio = { package = "shuttle-tokio" }`, never naming `shuttle-tokio/shuttle` itself, and which calls `tokio::time::clear_triggers` (present only in Shuttle's tokio::time): * without `--features shuttle`: fails with `cannot find function clear_triggers in module tokio::time`, ie. it resolved to real tokio * with `--features shuttle`: compiles, ie. the feature reached it Also fixes the shuttle-tokio version in the wrappers/README.md example, which said `1` where the crate is at 0.1.0. No CHANGELOG entry, matching the convention that release-prep PRs aggregate them.
This was referenced Aug 22, 2026
Revert the wrappers/README.md example back to `version = "1"`. The example was right and the crate version was wrong; shuttle-tokio is being republished as 1.0.0 to match the scheme the other wrappers follow, so the docs need no change. Point the enabler's own dependency and examples at `1` accordingly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
wrappers/README.mdhas documented ashuttle_enablercrate since #240, but the crate was never added. The instructions there could not be followed, and the[shuttle_enabler](shuttle_enabler)link was dead. This adds it.Why
A crate depending on several wrappers has to name every one of them in its own
shuttlefeature:That list is easy to get wrong, and getting it wrong is quiet. A missing entry does not fail the build; it leaves that dependency running its real implementation inside a Shuttle test, where the scheduler has no control over it. With
shuttle_enablerthe list is one entry, and adding a wrapped dependency later needs no change to it.What
The crate contains no code. It owns a
shuttlefeature that enables theshuttlefeature of the ten wrappers, plusdeterminizable_collections'deterministicfeature. Cargo compiles each crate once with the union of the features requested of it, so a downstream crate's ownshuttle-tokiodependency picks up the feature without naming it.Three choices worth a look during review:
shuttlefeature, so depending on this crate costs nothing when the feature is off.cargo check -p shuttle_enablercompiles no wrapper crates at all.default-features = falseeverywhere, so the crate contributes only theshuttlefeature and does not turn on other features on a downstream crate's behalf.Verification
The property that matters is that the feature actually reaches a downstream crate's own dependency, which building this crate alone does not prove. Tested with a scratch crate that depends on
shuttle_enablerand ontokio = { package = "shuttle-tokio" }, never namingshuttle-tokio/shuttleitself, callingtokio::time::clear_triggers(present only in Shuttle'stokio::time):cargo checkcannot find function clear_triggers in module tokio::time, ie. it resolved to real tokiocargo check --features shuttleAlso confirmed:
cargo check -p shuttle_enablerandcargo check -p shuttle_enabler --features shuttleboth clean, the latter building all 11 wrappers and resolvingshuttle-tokio v1.0.0.cargo check --workspace,cargo fmt --all -- --check,cargo clippy -p shuttle_enabler --all-targets --features shuttle -- -D clippy::all, andcargo doc --no-depsall clean withRUSTFLAGS=-Dwarnings.cargo tree -f "{p} [{f}]"on an isolated consumer shows 10 of the 11 wrappers receiving exactly[shuttle](or[deterministic]), confirming thedefault-features = falseneutrality. The one exception isshuttle-rand, which also getsdefaultbecausewrappers/tokio/impls/tokio-retrydepends on it withoutdefault-features = false. That predates this PR and I left it alone; happy to fix it here or separately if you'd like.Also
Adds a short explanation of the unification mechanism to
wrappers/README.md, and documents the version-skew failure mode there and in the new crate's README.Open questions
shuttle_enablerwith an underscore, matching whatwrappers/README.mdalready documents, though most wrappers use hyphens. Say the word if you'd rather rename it and update the docs instead.wrappers/README.mdalso documents atokio-version-importer-do-not-use-directlycrate for pinning, which likewise does not exist in the tree. Not touched here.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.