almost-enough 0.2.0

Batteries-included ergonomic extensions for the `enough` cooperative cancellation crate
Documentation
  • Coverage
  • 100%
    31 out of 31 items documented19 out of 28 items with examples
  • Size
  • Source code size: 71.65 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 6.6 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Links
  • imazen/enough
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • lilith

almost-enough

Batteries-included ergonomic extensions for the [enough] cooperative cancellation crate.

This crate provides all the concrete implementations and helpers for working with stop tokens. It re-exports everything from enough for convenience.

Quick Start

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 Overview

Type Feature Use Case
[Never] 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

StopExt Extension Trait

The [StopExt] trait adds combinator methods to any [Stop] implementation:

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());

Type Erasure with into_boxed()

Prevent monomorphization explosion at API boundaries:

# #[cfg(feature = "alloc")]
# fn main() {
use almost_enough::{Stopper, BoxedStop, Stop, StopExt};

fn outer(stop: impl Stop + 'static) {
    // Erase the concrete type to avoid monomorphizing inner()
    inner(stop.into_boxed());
}

fn inner(stop: BoxedStop) {
    // Only one version of this function exists
    while !stop.should_stop() {
        break;
    }
}

let stop = Stopper::new();
outer(stop);
# }
# #[cfg(not(feature = "alloc"))]
# fn main() {}

Hierarchical Cancellation with .child()

Create child stops that inherit cancellation from their parent:

# #[cfg(feature = "alloc")]
# fn main() {
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());
# }
# #[cfg(not(feature = "alloc"))]
# fn main() {}

Stop Guards (RAII Cancellation)

Automatically stop on scope exit unless explicitly disarmed:

# #[cfg(feature = "alloc")]
# fn main() {
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(())
}

fn risky_operation() -> Result<(), &'static str> {
    Ok(())
}

let source = Stopper::new();
do_work(&source).unwrap();
# }
# #[cfg(not(feature = "alloc"))]
# fn main() {}

Feature Flags

  • std (default) - Full functionality including timeouts
  • alloc - Arc-based types, into_boxed(), child(), StopDropRoll
  • None - Core trait and stack-based types only