Skip to main content

Module scope

Module scope 

Source
Expand description

Scoped goroutines — safe short-lived borrows.

scope is the goroutine equivalent of std::thread::scope: every goroutine spawned through the Scope handle is guaranteed to finish before scope returns, so the closures may safely borrow data from the calling goroutine’s stack frame without a 'static bound.

§How the lifetime safety works

The two lifetime parameters on Scope<'scope, 'env> encode the invariant:

  • 'env — the lifetime of data that goroutines are allowed to borrow (e.g. a &Vec<i32> from the surrounding function).
  • 'scope — the lifetime of the Scope reference itself; it lasts exactly as long as the closure passed to scope runs.
  • The bound 'env: 'scope ensures that borrowed data outlives the scope.

Inside Scope::go the closure’s 'scope lifetime is erased to 'static (via transmute) so it can be handed to the scheduler. This is sound because scope blocks (via WaitGroup::wait) until every spawned goroutine has called wg.done(), which happens only after the closure returns or panics — so no goroutine can outlive 'scope.

§Panic behaviour

go-lib goroutines are scheduled M:N across OS threads. Rust’s panic unwinding relies on C++ exception-handling (EH) machinery whose landing pads are registered per-OS-thread. Calling std::panic::resume_unwind after a goroutine has been parked and resumed (potentially on a different OS thread) would silently bypass the inner landing pad and reach the outer goroutine_entry catch — crashing.

Therefore:

  • ScopedJoinHandle::join returns std::thread::Result<R> rather than R, so the caller decides how to handle a scoped goroutine’s panic without crossing any scheduling boundary.
  • If the outer scope closure itself panics, scope catches it, waits for all goroutines, and then re-raises it with std::panic::panic_any — which starts a fresh panic on the current OS thread, always finding the correct landing pad.

§Example

go_lib::run(|| {
    let data = vec![1_i64, 2, 3, 4, 5];

    let sum = go_lib::scope(|s| {
        let h1 = s.go(|| data[..3].iter().sum::<i64>());
        let h2 = s.go(|| data[3..].iter().sum::<i64>());
        h1.join().unwrap() + h2.join().unwrap()
    });

    assert_eq!(sum, 15);
});

Structs§

Scope
A scope for spawning goroutines with bounded lifetimes.
ScopedJoinHandle
A handle to a goroutine spawned inside a Scope.

Functions§

scope
Run a closure that can spawn short-lived goroutines borrowing local data.