enough
Minimal cooperative cancellation trait for Rust.
A minimal, no_std trait for cooperative cancellation. Zero dependencies.
StopReason is 1 byte and check() compiles to a single boolean read from the stack.
For Library Authors
Accept impl Stop + 'static in your public API. See
Choosing a Signature below.
use ;
// Callers:
// decode(&data, Unstoppable)?; // no cancellation
// decode(&data, stopper)?; // with cancellation
Zero-Cost Default
use Unstoppable;
// Compiles away completely - zero runtime cost
let result = decode;
Optimizing Hot Loops with dyn Stop
Behind &dyn Stop, the compiler can't inline away Unstoppable::check(). Use may_stop() with Option<T> to eliminate that overhead:
use ;
Option<T: Stop> implements Stop: None is a no-op, Some(inner) delegates. The branch predictor handles the constant None/Some perfectly.
What's in This Crate
This crate provides only the core trait and types:
Stop- The cooperative cancellation traitStopReason- Why an operation stopped (Cancelled or TimedOut)Unstoppable- Zero-cost "never stop" implementationimpl Stop for Option<T: Stop>- No-op whenNone, delegates whenSome
For concrete cancellation implementations (Stopper, StopSource, timeouts, etc.), see almost-enough.
Choosing a Function Signature
Public API: impl Stop + 'static
One function per operation. Callers pass Unstoppable explicitly
for no cancellation:
use ;
// Callers:
// decode(&data, Unstoppable)?; // no cancellation
// decode(&data, stopper)?; // with cancellation
The 'static bound is needed for StopToken::new() internally.
Use impl Stop (without 'static) for embedded/no_std code that
accepts borrowed types like StopRef<'a>.
Internally: use StopToken (from almost-enough)
StopToken is the best all-around choice for internal code. Benchmarks
show it within 3% of fully-inlined generic for Unstoppable, and 25%
faster than generic for Stopper (due to the flattened Arc and
automatic Option optimization).
use Stop;
use StopToken;
StopToken handles the Unstoppable optimization automatically — no
may_stop() call needed. For parallel work, clone the StopToken
(cheap Arc increment). Stopper/SyncStopper convert at zero cost
via Into (same Arc, no double-wrapping).
Without almost-enough
Use &dyn Stop with may_stop().then_some(). The result is
Option<&dyn Stop> which implements Stop — None.check() returns
Ok(()), Some.check() delegates:
Future direction:
StopTokenmay move fromalmost-enoughintoenoughin a future release, so library authors can get erased + clonable stop tokens without the extra dependency.
Features
- None (default) -
no_stdcore:Stoptrait,StopReason,Unstoppable alloc- AddsBox<T>andArc<T>blanket impls forStopstd- Impliesalloc(kept for downstream compatibility)
See Also
almost-enough- All implementations:Stopper,StopSource,ChildStopper, timeouts, combinators, guardsenough-ffi- FFI helpers for C#, Python, Node.jsenough-tokio- Tokio CancellationToken bridge
License
MIT OR Apache-2.0