type Cursor = { slot: Int64, gen: Int64 }
A producer's cursor: a slot of this module's slab and the generation that was live when the stream took it.
Type to search, or try , or .
8 exports, from std/stream.vyrn.
The linear Stream<T> combinators, written in Vyrn.
Every combinator takes a Stream parameter, so it inherits the linearity rule: an abandoned map(...) result fails to compile for the same reason an abandoned fromArray(...) does. map, filter and take are lazy wrappers: a wrapper's cursor holds its source, its step pulls one element at a time, and its close releases the source, one release per stream down the chain. A cursor is a slot in this module's Slots<CursorCell>, so a cursor that outlives its stream traps as a dead handle. There is no merge-by-arrival and no channel: both need to know which source is ready, and streams have no concurrency.
The import graph shows the whole library.
type Cursor = { slot: Int64, gen: Int64 }
A producer's cursor: a slot of this module's slab and the generation that was live when the stream took it.
fn cursorGet(c: Cursor) -> Int64
Traps if the stream that owns the cursor is closed.
fn cursorSet(c: Cursor, v: Int64)
fn unfold<T>(seed: Int64, step: fn(Cursor) -> Option<T>) -> Stream<T>
A stream from a step function and a starting cursor.
step gets the stream's own cursor once per element: read it with cursorGet, write the next one with cursorSet, and answer Some(v) to yield or None to end. Nothing runs until a consumer asks, so a step that never answers None is an endless feed. The cursor is an Int64 because a seed type in the step's signature would be a type parameter of Stream<T>; other producer state goes in a second cursor the step closes over.
fn map<T, U>(s: Stream<T>, f: fn(T) -> U) -> Stream<U>
Applies f to every element the consumer asks for. s is consumed; the result is a new obligation.
The three wrappers repeat one shape by hand. A shared wrap(s, step) compiles and agrees on every engine, but it adds one indirect call per element per layer (map over unfold under take: +24%) and saves no lines.
fn filter<T>(s: Stream<T>, pred: fn(T) -> Bool) -> Stream<T>
Keeps only the elements for which pred holds.
A predicate that admits one in k asks its source about kn times to yield n; over an endless source where nothing passes, it asks forever.
fn take<T>(s: Stream<T>, n: Int64) -> Stream<T>
The first n elements (fewer if the stream is shorter; none if n <= 0). Asks its source exactly n times: the count is checked before each pull.
fn merge<T>(a: Stream<T>, b: Stream<T>) -> Stream<T>
Interleaves two streams one element at a time, draining whichever outlasts the other. Both inputs are consumed.
Eager, so an endless side hangs: a wrapper owns one source because a cursor holds one box. Wrap an endless side in take first.
This module carries no test block of its own.
5 programs in examples/ import this module. Each runs as WebAssembly and as a native binary.