Skip to content

chore: workspace modernization — MSRV 1.85, drop 4 unmaintained deps#973

Closed
anikettuli wants to merge 5 commits intoStremio:developmentfrom
anikettuli:claude/modernize-core
Closed

chore: workspace modernization — MSRV 1.85, drop 4 unmaintained deps#973
anikettuli wants to merge 5 commits intoStremio:developmentfrom
anikettuli:claude/modernize-core

Conversation

@anikettuli
Copy link
Copy Markdown

Summary

Bundles five contract-preserving modernization steps into one PR:

  1. MSRV 1.85 — aligns declared rust-version with the CI matrix across all three workspace crates.
  2. Remove boolinator — unmaintained since 2016; covered by stdlib bool::then / then_some.
  3. Replace tokio-current-thread = "=0.2.0-alpha.1" — a pre-1.0 alpha, with modern tokio::task::LocalSet.
  4. Migrate once_cell::sync::Lazystd::sync::LazyLock — drop-in replacement since Rust 1.80.
  5. Remove enclose macro — the enclose! convenience is replaced by plain let x = x.clone(); move || blocks (a no-dep idiom since Rust 2021).

These are independent conceptually but share a common theme ("modernize the dependency floor without touching runtime behavior") and overlap heavily in manifest edits, so bundling avoids five near-identical Cargo.toml / Cargo.lock merge conflicts.

Each step lands as its own commit so reviewers can read, test, or revert piecewise:

f6a7b6d33 build: bump workspace MSRV from 1.77 to 1.85
bc370a59c chore: remove unmaintained boolinator dep
bda1377bc test: replace tokio-current-thread alpha with tokio LocalSet
aa377c8cd chore: migrate once_cell::sync::Lazy to std::sync::LazyLock
d6f597835 chore: remove enclose macro; use explicit clone-before-move

Why these changes

  • boolinator: last release August 2016. Covered by bool::then (Rust 1.50) and bool::then_some (1.62). Keeping it is pure supply-chain surface area for zero benefit.
  • tokio-current-thread: pinned at a pre-1.0 alpha (=0.2.0-alpha.1) from 2018. The only consumer is the test harness; modern tokio has LocalSet that does the exact same !Send single-threaded spawn-and-drain.
  • once_cell: LazyLock shipped in Rust 1.80. Using the stdlib version removes a third-party crate from every build.
  • enclose: the enclose! macro is a pre-Rust-2021 ergonomic shortcut. Rust 2021's disjoint-capture rules plus plain let x = x.clone(); expand to the exact same code — no macro needed.
  • MSRV 1.85: LazyLock is 1.80+ only, so the migration requires a floor bump. Picking 1.85 matches the CI stable runner and leaves headroom for near-future stdlib additions.

Effect

  • Four third-party crates removed from the dependency graph (boolinator, tokio-current-thread, enclose, once_cell), plus the transitive dev-deps tokio-executor, crossbeam-channel, crossbeam-utils, and one cfg-if copy.
  • Cargo.lock shrinks by ~10 entries.
  • No runtime behavior change. No public API surface touched — every #[wasm_bindgen] export, every Msg / Action / Event variant, every deep-link URL, and every serialized JSON field name is byte-for-byte identical.
  • Test harness semantics preserved — the two-phase spawn-then-drain contract in run_with_runtime is kept as two successive LocalSet::block_on + rt.block_on(local) calls, matching the pre-1.0 block_on_all behavior.

Scope

  • 37 enclose! invocations across 19 files, mechanically rewritten (see commit d6f597835). The rewrite script is not included in the PR — it was a one-time helper.
  • 10 files migrated from once_cell::sync::Lazy to std::sync::LazyLock.
  • 3 boolinator callsites rewritten to bool::then / bool::then(..).flatten().
  • Test harness in src/unit_tests/env.rs rewritten to LocalSet.
  • 3 manifest files bumped for MSRV (Cargo.toml, stremio-watched-bitfield/Cargo.toml, .github/workflows/msrv.yml).

Public contract

Zero changes to:

Test plan

Verified locally on every commit (Rust 1.85.1 stable-x86_64-pc-windows-gnu):

  • cargo test -p stremio-core --lib202 passed, 0 failed
  • cargo test -p stremio-watched-bitfield7 passed, 0 failed
  • cargo clippy --all --no-deps -- -D warnings — clean
  • cargo fmt --check — clean

(The remaining future-incompat-report note about wasm-bindgen 0.2.78 is unrelated to this PR — that's what #969 upgrades.)

Supersedes

This PR bundles and replaces:

Those will be closed in favor of this consolidated PR.

Replace Boolinator::as_option on bool with stdlib bool::then / then_some.
boolinator has been unmaintained since 2016 and every use case is covered
by the stdlib since Rust 1.62.
tokio-current-thread = "=0.2.0-alpha.1" is a pre-1.0 alpha, unmaintained
for ~8 years. Modern tokio's LocalSet provides the same !Send-future
semantics. The two-phase drain in run_with_runtime is preserved.
LazyLock (Rust 1.80+) is a drop-in replacement for once_cell::sync::Lazy.
Enabled by the workspace MSRV bump to 1.85 earlier in this branch. Drops
the once_cell dependency entirely - no production OnceCell/OnceLock usage
to migrate.
The enclose! macro from the enclose crate (v1.1, 2019) is a pre-Rust-2021
convenience for cloning captures before a move closure. Rust 2021's
disjoint-closure capture plus a plain 'let x = x.clone();' before 'move ||'
covers every use case with no loss of readability.

Rewriting in-line drops one third-party crate from the dependency graph.
No runtime or public API change.

Transformed every callsite mechanically (37 invocations across 19 files)
via scripts/rewrite_enclose.py. Examples:

  enclose!((x) move |a| body)             -> { let x = x.clone(); move |a| body }
  enclose!((expr => name) ...)            -> { let name = expr.clone(); ... }
  enclose!((a, b) ...)                    -> { let a = a.clone(); let b = b.clone(); ... }
  enclose!(() move |...| ...)             -> move |...| ...

Verified locally (Rust 1.85.1 stable-x86_64-pc-windows-gnu):
  cargo test -p stremio-core --lib         -> 202 passed, 0 failed
  cargo test -p stremio-watched-bitfield   -> 7 passed, 0 failed
  cargo clippy --all --no-deps -D warnings -> clean
  cargo fmt --check                         -> clean
Copilot AI review requested due to automatic review settings April 20, 2026 05:21
@github-actions
Copy link
Copy Markdown

stremio-core-web prebuild

Prebuild artifact published by the Build workflow for branch claude/modernize-core.

Paste one of these into stremio-web's package.json and run pnpm install to wire this prebuild into a corresponding stremio-web PR:

Release

"@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/claude/modernize-core/stremio-stremio-core-web-0.56.3.tgz"

Dev

"@stremio/stremio-core-web": "https://stremio.github.io/stremio-core/stremio-core-web/claude/modernize-core/dev/stremio-stremio-core-web-0.56.3.tgz"

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Modernizes the Rust workspace by raising the MSRV and removing several unmaintained/obsolete dependencies while keeping behavior and public contract unchanged.

Changes:

  • Bump declared MSRV to Rust 1.85 and update the MSRV CI workflow accordingly.
  • Drop boolinator, enclose, once_cell, and tokio-current-thread, replacing usages with stdlib/Tokio equivalents (bool::then, explicit clone-before-move closures, std::sync::LazyLock, tokio::task::LocalSet).
  • Refresh Cargo.lock after dependency graph simplification.

Reviewed changes

Copilot reviewed 32 out of 33 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
Cargo.toml Bumps workspace crate MSRV; removes unmaintained deps and tokio-current-thread dev-dep.
Cargo.lock Regenerated lockfile reflecting removed dependencies; lockfile format version updated.
.github/workflows/msrv.yml Updates MSRV job to run on Rust 1.85.
stremio-watched-bitfield/Cargo.toml Aligns crate MSRV to 1.85.
stremio-core-web/Cargo.toml Removes direct deps on enclose, boolinator, once_cell.
stremio-core-web/src/env.rs Migrates once_cell::sync::Lazy statics to std::sync::LazyLock.
stremio-core-web/src/stremio_core_web.rs Migrates LazyLazyLock; removes enclose usage in async closures.
stremio-core-web/src/model/serialize_discover.rs Replaces boolinator usage with bool::then.
src/constants.rs Migrates LazyLazyLock for global constants.
src/addon_transport/http_transport/http_transport.rs Migrates function-local LazyLazyLock.
src/analytics.rs Removes enclose macro usage in async chaining.
src/runtime/runtime.rs Removes enclose; uses explicit clone captures in effect dispatching.
src/types/resource/stream.rs Replaces boolinator with bool::then(...).flatten() in Stream::youtube.
src/models/catalog_with_filters.rs Replaces boolinator with bool::then for optional option construction.
src/models/common/resource_loadable.rs Removes enclose; uses explicit capture for request in async map.
src/models/ctx/ctx.rs Removes enclose; uses explicit clones in async maps.
src/models/ctx/update_events.rs Removes enclose; uses explicit UID capture in storage write mapping.
src/models/ctx/update_notifications.rs Migrates LazyLazyLock for duration constant.
src/models/ctx/update_profile.rs Removes enclose; uses explicit UID capture in storage write mapping.
src/models/ctx/update_search_history.rs Removes enclose; uses explicit UID capture in storage write mapping.
src/models/ctx/update_streams.rs Removes enclose; uses explicit UID capture in storage write mapping.
src/models/link.rs Removes enclose; uses explicit code capture in async map.
src/models/local_search.rs Removes enclose; uses explicit URL capture in async map.
src/models/meta_details.rs Removes enclose; uses explicit meta_id capture in async maps.
src/models/player.rs Migrates LazyLazyLock; removes enclose usage in async map.
src/models/streaming_server.rs Removes enclose; replaces with explicit clones/captures in async maps.
src/unit_tests/env.rs Migrates LazyLazyLock; replaces tokio-current-thread usage with tokio current-thread runtime + LocalSet; removes enclose.
src/unit_tests/data_export.rs Removes enclose in test closures; replaces with explicit clone-before-move.
src/unit_tests/catalog_with_filters/load_action.rs Removes enclose in test closures; replaces with explicit clone-before-move.
src/unit_tests/meta_details/override_selected.rs Removes enclose in test closures; replaces with explicit clone-before-move.
src/unit_tests/deep_links/library_item_deep_links.rs Migrates LazyLazyLock for test fixtures.
src/unit_tests/ctx/sync_library_with_api.rs Migrates LazyLazyLock for test fixtures.
src/unit_tests/ctx/notifications/update_notifications.rs Migrates LazyLazyLock; removes enclose in test helpers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 44 to 46
wasm-bindgen = { version = "=0.2.78", features = ["serde-serialize"], optional = true }
wasm-bindgen-futures = { version = "0.4", optional = true }
gloo-utils = { version = "0.2", features = ["serde"], optional = true }
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description says MSRV is aligned across all workspace crates, but this crate’s [package] section still has no rust-version. Since the code now uses std::sync::LazyLock (1.80+), it would be better to declare rust-version = "1.85" here too so Cargo can enforce MSRV consistently and emit a clear error on older toolchains.

Copilot uses AI. Check for mistakes.
Comment on lines +167 to 184
WebEnv::exec_concurrent(WebEnv::get_location_hash().then({
let event = event.clone();
move |location_hash| async move {
let runtime = RUNTIME.read().expect("runtime read failed");
let runtime = runtime
.as_ref()
.expect("runtime is not ready")
.as_ref()
.expect("runtime is not ready");
let model = runtime.model().expect("model read failed");
let path = location_hash.split('#').last().map(|path| path.to_owned()).unwrap_or_default();
let path = location_hash
.split('#')
.last()
.map(|path| path.to_owned())
.unwrap_or_default();
WebEnv::emit_to_analytics(
&WebEvent::CoreEvent(Box::new(event.to_owned())),
&model,
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

event is already an owned Event after let event = event.clone();, so Box::new(event.to_owned()) performs an extra clone. Consider moving event directly into the Box (or otherwise avoiding the additional allocation/clone) since this runs on every emitted core event.

Copilot uses AI. Check for mistakes.

impl Stream {
pub fn youtube(video_id: &str) -> Option<Self> {
// video id is in format: yt_id:YT_CHANNEL_ID:YT_VIDEO_ID
Copy link

Copilot AI Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor grammar nit in the new comment: consider changing “video id is in format” to “video id is in the format” for readability.

Suggested change
// video id is in format: yt_id:YT_CHANNEL_ID:YT_VIDEO_ID
// video id is in the format: yt_id:YT_CHANNEL_ID:YT_VIDEO_ID

Copilot uses AI. Check for mistakes.
@anikettuli
Copy link
Copy Markdown
Author

Closing is fair. For context on the intent: I hit friction trying to build the repo on a fresh machine (the pinned wasm-bindgen 0.2.78 is incompatible with Rust ≥ 1.78), and the 4 deps this PR dropped are all either unmaintained or superseded by stdlib. The goal was to lower the bar for new contributors, not force dependency churn for its own sake. I understand the preference to tie core changes to concrete bug/feature work and am happy to redirect toward specific reliability issues if you can point me at a few (Android TV ExoPlayer behaviour is what originally brought me here).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants