Skip to content

feat: cancelable crate#465

Open
afoxman wants to merge 15 commits into
mainfrom
cancelable-crate
Open

feat: cancelable crate#465
afoxman wants to merge 15 commits into
mainfrom
cancelable-crate

Conversation

@afoxman

@afoxman afoxman commented Jun 2, 2026

Copy link
Copy Markdown

This PR introduces a new crate named cancelable.

It models C# cancelation tokens and sources in Rust, aimed at improving the accuracy of C# -> Rust code translation.

Copilot AI review requested due to automatic review settings June 2, 2026 01:14

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a new workspace crate, cancelable, providing C#-style cooperative cancellation primitives (token + source) plus a Future combinator to surface cancellation as a typed error.

Changes:

  • Introduces cancelable crate with CancellationToken, CancellationTokenSource, and parent-linked cancellation.
  • Adds WithCancellationExt::with_cancellation to wrap futures and return Result<_, Canceled> when canceled.
  • Wires the new crate into workspace metadata (workspace deps, root README/CHANGELOG, lockfile) and adds crate assets (logo/favicon).

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
README.md Adds cancelable to the workspace crate list.
CHANGELOG.md Adds cancelable to the top-level changelog index.
Cargo.toml Registers cancelable as a workspace dependency entry.
Cargo.lock Adds the new cancelable package entry and deps.
crates/cancelable/Cargo.toml Defines the new crate package metadata and dependencies.
crates/cancelable/CHANGELOG.md Adds an initial changelog stub for the new crate.
crates/cancelable/README.md Adds crate-level README content (doc2readme output).
crates/cancelable/logo.png Adds crate logo via Git LFS.
crates/cancelable/favicon.ico Adds crate favicon via Git LFS.
crates/cancelable/src/lib.rs Crate root docs and exports for token/source and future extension trait.
crates/cancelable/src/token.rs Implements token/source state, subscriptions, and linked sources (+ tests).
crates/cancelable/src/future.rs Implements with_cancellation future wrapper and Canceled error (+ tests).

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

Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/lib.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/future.rs Outdated
Comment thread crates/cancelable/src/future.rs Outdated
Comment thread crates/cancelable/src/token.rs
@codecov

codecov Bot commented Jun 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.0%. Comparing base (bf1ba72) to head (ff067d4).

Additional details and impacted files
@@           Coverage Diff            @@
##             main     #465    +/-   ##
========================================
  Coverage   100.0%   100.0%            
========================================
  Files         335      337     +2     
  Lines       25586    26131   +545     
========================================
+ Hits        25586    26131   +545     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions

github-actions Bot commented Jun 2, 2026

Copy link
Copy Markdown

⚠️ Breaking Changes Detected

error: failed to retrieve local crate data from git revision

Caused by:
    0: failed to retrieve manifest file from git revision source
    1: possibly due to errors: [
         failed when reading /home/runner/work/oxidizer/oxidizer/target/semver-checks/git-origin_main/2cae70143277a47f7fd01c2b353eeee72c22ffb7/scripts/crate-template/Cargo.toml: TOML parse error at line 9, column 26
         |
       9 | keywords = ["oxidizer", {{CRATE_KEYWORDS}}]
         |                          ^
       missing key for inline table element, expected key
       : TOML parse error at line 9, column 26
         |
       9 | keywords = ["oxidizer", {{CRATE_KEYWORDS}}]
         |                          ^
       missing key for inline table element, expected key
       ,
         failed to parse /home/runner/work/oxidizer/oxidizer/target/semver-checks/git-origin_main/2cae70143277a47f7fd01c2b353eeee72c22ffb7/Cargo.toml: no `package` table,
       ]
    2: package `cancelable` not found in /home/runner/work/oxidizer/oxidizer/target/semver-checks/git-origin_main/2cae70143277a47f7fd01c2b353eeee72c22ffb7

Stack backtrace:
   0: anyhow::error::<impl anyhow::Error>::msg
   1: cargo_semver_checks::rustdoc_gen::RustdocFromProjectRoot::get_crate_source
   2: cargo_semver_checks::rustdoc_gen::StatefulRustdocGenerator<cargo_semver_checks::rustdoc_gen::CoupledState>::prepare_generator
   3: cargo_semver_checks::Check::check_release::{{closure}}
   4: cargo_semver_checks::Check::check_release
   5: cargo_semver_checks::exit_on_error
   6: cargo_semver_checks::main
   7: std::sys::backtrace::__rust_begin_short_backtrace
   8: main
   9: <unknown>
  10: __libc_start_main
  11: _start

If the breaking changes are intentional then everything is fine - this message is merely informative.

Remember to apply a version number bump with the correct severity when publishing a version with breaking changes (1.x.x -> 2.x.x or 0.1.x -> 0.2.x).

@ralfbiedert

Copy link
Copy Markdown
Collaborator

I'm not particularly fond of the naming and structure of this, is there a reason we don't align this more with how Tokio does it?

@sandersaares sandersaares left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks nice! A lot simpler than I feared it would be and I like how well it enables .NET parity to be modeled. The subscriber leak that Copilot raised is a concern, though.

Comment thread crates/cancelable/src/lib.rs Outdated
Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs
1. Disable miri for tokio tests (not supported)
2. Mutation testing fixes. Tests were hanging, but now time out and fail after 5 secs, giving them plenty of time to stabilize (e.g. not flaky).
3. Rename future extension to CancelableExt with method cancelable() and state struct Cancelable.
4. Document atomic ordering decisions
5. Propagate poisoned lock errors as panics
6. Avoid boxing when using the subscriber list to capture linked token relationships.
7. Unregister linked child token sources from their parents on Drop.
8. Update doc comments
Copilot AI review requested due to automatic review settings June 3, 2026 01:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/future.rs Outdated
Comment thread crates/cancelable/src/future.rs Outdated
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/token.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/future.rs
Copilot AI review requested due to automatic review settings June 3, 2026 19:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 3 comments.

Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread README.md
Comment thread crates/cancelable/src/future.rs
Copilot AI review requested due to automatic review settings June 3, 2026 23:30

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs Outdated
Comment thread crates/cancelable/src/token.rs Outdated

@ralfbiedert ralfbiedert left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Still same comment I left earlier. I think this needs a motivation why it looks like the C# version, and not like Tokio's flavor of that. In the end we try to solve Rust problems, not C# problems.

@afoxman

afoxman commented Jun 4, 2026

Copy link
Copy Markdown
Author

Still same comment I left earlier. I think this needs a motivation why it looks like the C# version, and not like Tokio's flavor of that. In the end we try to solve Rust problems, not C# problems.

I don't know Tokio well enough to know what this means. Can you give some examples of things you'd like changed? Is it runtime differences? Naming? Different data modeling? Contractual differences?

Copilot AI review requested due to automatic review settings June 4, 2026 16:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 4 comments.

Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/lib.rs
Comment thread crates/cancelable/src/future.rs
Comment thread crates/cancelable/src/future.rs
@ralfbiedert

Copy link
Copy Markdown
Collaborator

I don't know Tokio well enough to know what this means. Can you give some examples of things you'd like changed? Is it runtime differences? Naming? Different data modeling? Contractual differences?

Tokio has a CancellationToken in the tokio_util crate; additional documentation is here in the 'Shutdown' section.

My criticism is that this API looks like a port from C#, for example having CT and CTS, how linked tokens are created, ... If at the end of a design analysis this is still the best API then of course it's fine (although CTS is too much of a name for Rust IMO), but I haven't seen any conversation where this was compared against Tokio's or any other Rust-based approach.

Very generally, the first reflex for crates like this should be looking into "how does Rust solve this C# problem", not "how does C# solve this C# problem". What would be good is looking at what crates already exist out there. There is at least Tokio's, maybe smol tried solving this too?

@afoxman

afoxman commented Jun 5, 2026

Copy link
Copy Markdown
Author

tokio_util::CancellationToken looks a lot like what I've got here for my CancellationToken. APIs even have mostly the same names. I don't have a drop-guard, but that can be added to my design if it is needed.

So I think what you're hinting at is that you don't like the idea of a CancellationTokenSource. This exists because I offer more than Tokio's solution -- I let callers register for callbacks so they can define their own cancellation logic rather than embedding it into the task being canceled.

It's a different approach. That's why it is a bit different.

I'd argue this does in fact solve a big Rust problem, and Tokio's cancellation token is evidence that something like this is needed. My impl is different, which is one reason it exists. Further, though, and more importantly, the problem of code translation from C# to Rust is front and center for Microsoft. It is a worthy problem to solve, and this helps with that, giving developers and AI agents something very familiar to work with - something missing from the Rust ecosystem.

@afoxman afoxman enabled auto-merge (squash) June 5, 2026 17:16
Copilot AI review requested due to automatic review settings June 5, 2026 17:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 11 out of 12 changed files in this pull request and generated 2 comments.

Comment thread crates/cancelable/src/lib.rs
Comment thread crates/cancelable/src/future.rs
@schgoo

schgoo commented Jun 5, 2026

Copy link
Copy Markdown
Collaborator

@ralfbiedert I'm approving to unblock @afoxman for now. If you're game, I think we should have a deeper discussion about your concerns here, and what recommendations you have for the API.

@afoxman afoxman disabled auto-merge June 5, 2026 20:06
@afoxman

afoxman commented Jun 5, 2026

Copy link
Copy Markdown
Author

It sounds like this needs more higher-level discussion, so I'm going to land it in an internal repo for now. After we have some consensus on how to proceed, I can get this PR landed here (with any needed changes).

@ralfbiedert

Copy link
Copy Markdown
Collaborator

It sounds like this needs more higher-level discussion,

Yes, let's have a call.

I'd argue this does in fact solve a big Rust problem, and Tokio's cancellation token is evidence that something like this is needed.

If we looked at existing implementations and decided it's better, sure.

Further, though, and more importantly, the problem of code translation from C# to Rust is front and center for Microsoft. It is a worthy problem to solve, and this helps with that, giving developers and AI agents something very familiar to work with

I don't buy that argument. Relative to all other code, cancellation is a tiny corner of the problem space. Everything else in that picture already looks and acts differently, for good reason.

  • C# has reflection, Rust doesn't,
  • C# has a GC, Rust doesn't,
  • C#'s static and link-model is different from Rust's,
  • C#'s async runtime interaction with the language works differently in Rust,
  • C# doesn't have an equivalent of Rust's Future drop cancellation (it couldn't even express that if it wanted to due to lack of move semantics)

When porting infrastructure code, the goal can't be to have APIs that look identical so "people have something familiar to worth with"; there is so much impedance mismatch in the rest of the language that I don't even know what that would mean at scale.

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.

7 participants