Structured concurrency

Ordinary calls wait. fork creates a Task<T> and await task yields T. Awaiting a Vec<Task<T>> consumes it and yields Vec<T> in vector order. If T is a Result, each application error remains a value to handle. The structured-concurrency concepts guide explains the motivation and lifecycle before this reference's syntax.

A scope owns its child tasks and produces a value after their cleanup. A plain call in a scope is still a call; it does not implicitly start a task.

fn left() -> i64 { 20 }
fn right() -> i64 { 22 }
fn main() {
    let total = scope {
        let a = fork left();
        let b = fork right();
        (await a) + (await b)
    };
    println(total);
}

await fork [left(), right()] collects a vector; the parenthesized batch form collects a tuple. Each batch expression first creates a task.

scope within duration { ... } handle failure { ... } bounds structured work. A fault or cancellation settles children and cleanup before recovery; an ordinary Err does not trigger it. Parent cancellation continues outward. Cancellation is cooperative and cannot skip resource cleanup.

race chooses the first completion, including an ordinary Err, and cleans up losers. select uses value from source => ... and after duration => .... Ordinary calls, tasks, timers, actor calls, and Stream<T>.recv() are supported selection sources. Adapted file and socket stream readiness is not a selectable source. Actor streams use ordinary for, without await.

Streams and sinks

Hew uses Stream<T> and Sink<T> for in-memory pipes, files, split sockets, process pipes, and actor receive gen fn streams; there is no separate channel type. std.stream.pipe(capacity) creates an in-memory pair. A sink waits in send, reports a closed reader as a typed error, and publishes clean end-of-data with finish or close. A stream's recv returns Option<T>, where None means clean end-of-data, and a for loop drains it. Closing a stream discards queued values and performs their normal ownership cleanup.