Skip to content

embedded-io-async: clarify cancel safety semantics for Read and Write#734

Closed
aki1770-del wants to merge 1 commit intorust-embedded:masterfrom
aki1770-del:fix/async-read-cancel-safety-docs-719
Closed

embedded-io-async: clarify cancel safety semantics for Read and Write#734
aki1770-del wants to merge 1 commit intorust-embedded:masterfrom
aki1770-del:fix/async-read-cancel-safety-docs-719

Conversation

@aki1770-del
Copy link
Copy Markdown

Fixes #719

Problem

The documentation for Read::read and Write::write in embedded-io-async used permissive language — "implementations are encouraged" and "implementations should document" — that left both callers and implementors without a clear contract. Issue #719 identifies the concrete failure mode this ambiguity enables:

When a read() future is dropped mid-transfer, bytes already received from the hardware FIFO or DMA buffer are silently discarded. No error is returned. The caller has no way to detect or recover from the data loss. In safety-critical embedded contexts (CAN/UART frames, ISO 26262), this is a silent data loss that can propagate through state machines without triggering any diagnostic path.

Fix

Rewrite the cancel-safety sections using normative SHOULD/MUST language and a dedicated # Cancel Safety heading (consistent with Tokio's convention):

  • States explicitly: this method is NOT guaranteed to be cancel-safe by default
  • Names the concrete failure mode: bytes in hardware FIFO/DMA may be silently dropped
  • Requires implementations that cannot guarantee cancel safety to MUST document this
  • Gives callers actionable guidance: run the future to completion rather than relying on cancel safety
  • References the future CancelSafeRead marker trait path for opt-in

The PR changes documentation only. No trait methods are added, no signatures change, no semver bump required. The architectural path to a CancelSafeRead marker trait (issue #719's long-term ask) is left for a follow-up RFC.

Existing Behavior Audit (OPS-RULE-016)

File Line Current state
embedded-io-async/src/lib.rs 49–56 Read::read cancel-safety: "encouraged", "should document" — no normative contract
embedded-io-async/src/lib.rs 119–126 Write::write cancel-safety: identical permissive framing
PR #469 ("io: expand docs", 2023-07-12) Prior documentation pass; introduced "encouraged" language that this PR strengthens

Scope Classification (OPS-RULE-017)

Category (b): Minor enhancement (documentation). No trait method signatures changed. No API-breaking change. A normative documentation tightening for existing behavior that was already the intended semantic, per the issue discussion. A full API change (new CancelSafeRead trait) would be category (c) requiring RFC — that is out of scope here.

Test

cargo check -p embedded-io-async passes. Documentation-only changes require no additional test code; the trait method signatures are unchanged.

Prior Art (OPS-RULE-018)

  1. PR io: expand docs. #469"io: expand docs" (merged 2023-07-12) — the prior documentation pass that added "encouraged" language; this PR closes the gap that io: expand docs. #469 opened by making the non-guarantee explicit
  2. Issue Explore DMA-based APIs built on top of &'static mut references #37"Explore DMA-based APIs built on top of &'static mut references" (open, 2018) — root structural reason cancel safety is non-trivial for hardware FIFO implementations; the DMA buffer ownership problem this fix warns about
  3. PR Add BufReader impl #627"Add BufReader impl" (open) — concrete mechanism by which cancel safety can be achieved at the adapter layer without trait changes; this PR's documentation explicitly allows for that approach

AI-assisted — authored with Claude, reviewed by Komada.

…dded#719)

The previous documentation used permissive language ("encouraged",
"implementations should document") that left callers uncertain about
what happens to data in flight when a future is dropped mid-transfer.

Replace the vague encouragement with normative documentation that:
- States explicitly the method is NOT cancel-safe by default
- Describes the concrete failure mode: bytes already received from
  hardware FIFO/DMA may be silently discarded with no error returned
- Uses SHOULD/MUST language consistent with the rest of the trait docs
- Mentions the CancelSafeRead marker trait path for future opt-in
- Gives callers actionable guidance (run future to completion)

This follows the pattern established by Tokio's cancel-safety
documentation and PR rust-embedded#469 ("io: expand docs"), closing the gap that
issue rust-embedded#719 identified.

Fixes rust-embedded#719

Signed-off-by: aki1770-del <aki1770@gmail.com>
@aki1770-del aki1770-del requested a review from a team as a code owner April 11, 2026 19:18
@Dirbaio
Copy link
Copy Markdown
Member

Dirbaio commented Apr 11, 2026

As far as I can tell the old and new wording is equivalent (implementations aren't required to be cancel-safe, implementations should document whether they are cancel-safe or not). So this PR is just a reword, it doesn't "fix" anything.

I personally find RFC-style MUST, SHOULD, MAY somewhat obnoxious to read, and it feels out of place here since we don't use it in the rest of rustdocs.

@Dirbaio Dirbaio closed this Apr 11, 2026
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.

Cancellation safety of Read::read and Write::write in embedded-io-async

2 participants