Module cancel_safe

Source
Expand description

Utilities to verify cancellation safety. Utilities for testing cancel safety of futures.

§What does “cancel-safe” mean?

A future is cancel-safe if, at any Poll::Pending boundary:

  1. State remains valid – dropping the future there does not violate external invariants or leave shared state corrupted.
  2. Restartability holds – from that state, constructing a fresh future for the same logical operation can still run to completion and produce the expected result.
  3. No partial side effects – cancellation never leaves behind a visible “half-done” action; effects are either not started, or fully completed in an idempotent way.

§Why cancel-safety matters

Executors are free to drop futures after any Poll::Pending. This means that cancellation is not an exceptional path – it is part of the normal contract. A cancel-unsafe future can leak resources, corrupt protocol state, or leave behind truncated I/O.

§What this module offers

This module provides helpers (assert_cancel_safe, assert_cancel_safe_async) that:

  • drive a future to completion once, counting its yield points,
  • then for every possible cancellation boundary k, poll a fresh future k times, drop it, and finally ensure a new run still produces the expected result.

§Examples

  • ✓ Pure/logical futures: simple state machines with no I/O (e.g. yields twice, then return 42).
  • ✓ Framed writers that stage bytes internally and only commit once the frame is fully written.
  • ✗ Writers that flush a partial frame before returning Pending.
  • ✗ Futures that consume from a shared queue before Pending and drop without rollback.

Functions§

assert_cancel_safe
Runtime-independent version: on each Poll::Pending, we just poll again. Suitable for pure/logical futures that don’t rely on timers, IO, or other external progress driven by an async runtime.
assert_cancel_safe_async
Cancel-safety check for async futures. On every Poll::Pending, runs on_pending().await to drive external progress (e.g. advancing a paused clock or IO). Cancels at each yield boundary and ensures a fresh run still produces expected.