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.