| Crates.io | almost-enough |
| lib.rs | almost-enough |
| version | 0.3.1 |
| created_at | 2026-01-11 08:49:28.4506+00 |
| updated_at | 2026-01-18 07:50:58.835033+00 |
| description | Batteries-included ergonomic extensions for the `enough` cooperative cancellation crate |
| homepage | |
| repository | https://github.com/imazen/enough |
| max_upload_size | |
| id | 2035431 |
| size | 78,547 |
Batteries-included ergonomic extensions for the enough cooperative cancellation crate.
While enough provides only the minimal Stop trait, this crate provides all concrete implementations, combinators, and helpers. It re-exports everything from enough for convenience.
use almost_enough::{Stopper, Stop};
let stop = Stopper::new();
let stop2 = stop.clone(); // Clone to share
// Pass to operations
assert!(!stop2.should_stop());
// Any clone can cancel
stop.cancel();
assert!(stop2.should_stop());
| Type | Feature | Use Case |
|---|---|---|
Unstoppable |
core | Zero-cost "never stop" |
StopSource / StopRef |
core | Stack-based, borrowed, zero-alloc |
FnStop |
core | Wrap any closure |
OrStop |
core | Combine multiple stops |
Stopper |
alloc | Default choice - Arc-based, clone to share |
SyncStopper |
alloc | Like Stopper with Acquire/Release ordering |
ChildStopper |
alloc | Hierarchical parent-child cancellation |
BoxedStop |
alloc | Type-erased dynamic dispatch |
WithTimeout |
std | Add deadline to any Stop |
std (default) - Full functionality including timeoutsalloc - Arc-based types, into_boxed(), child(), guardsno_std compatible)The StopExt trait adds combinator methods to any Stop:
use almost_enough::{StopSource, Stop, StopExt};
let timeout = StopSource::new();
let cancel = StopSource::new();
// Combine: stop if either stops
let combined = timeout.as_ref().or(cancel.as_ref());
assert!(!combined.should_stop());
cancel.cancel();
assert!(combined.should_stop());
Create child stops that inherit cancellation from their parent:
use almost_enough::{Stopper, Stop, StopExt};
let parent = Stopper::new();
let child = parent.child();
// Child cancellation doesn't affect parent
child.cancel();
assert!(!parent.should_stop());
// But parent cancellation propagates to children
let child2 = parent.child();
parent.cancel();
assert!(child2.should_stop());
Automatically cancel on scope exit unless explicitly disarmed:
use almost_enough::{Stopper, StopDropRoll};
fn do_work(source: &Stopper) -> Result<(), &'static str> {
let guard = source.stop_on_drop();
// If we return early or panic, source is stopped
risky_operation()?;
// Success! Don't stop.
guard.disarm();
Ok(())
}
Prevent monomorphization explosion at API boundaries:
use almost_enough::{Stopper, BoxedStop, Stop, StopExt};
fn outer(stop: impl Stop + 'static) {
// Erase the concrete type
inner(stop.into_boxed());
}
fn inner(stop: BoxedStop) {
// Only one version of this function exists
while !stop.should_stop() {
break;
}
}
enough - Minimal core trait (for library authors)enough-tokio - Tokio CancellationToken bridgeenough-ffi - FFI helpers for C#, Python, Node.jsMIT OR Apache-2.0