std/stream
std/stream
Section titled “std/stream”std/stream — byte-stream value backing the eventual HttpRequest.body: Stream migration (docs/STDLIB-DESIGN-RESEARCH.md Rec §1). Phase 1 (this PR): in-memory buffer-backed Stream with a data: u8[] payload + a pos: i32 read cursor. Reads advance the cursor; .read_all_string() / .read_all() consume the remainder. The buffer is allocated up-front; no lazy / chunked reads yet. Phase 2: replace the buffer with a host-side reader that pulls bytes on demand (wasi:http/incoming-body for wasi-http; TCP socket for tcp_serve). The lang-side API shape stays identical — handler code written against the Phase 1 surface keeps working under Phase 2 without changes. bytes is u8[] throughout the codebase (no separate type alias today). Stream constructors / readers all use u8[] for the byte-array side.
stream_from_bytes
Section titled “stream_from_bytes”pub function stream_from_bytes(bs: u8[]): Streamstream_from_bytes(bs) — wrap a u8[] buffer as a
Stream. The Stream owns the buffer; subsequent reads
advance the cursor.
stream_from_string
Section titled “stream_from_string”pub function stream_from_string(s: string): Streamstream_from_string(s) — wrap a string’s bytes as a
Stream. Cheap byte conversion (s.bytes() returns the
fresh u8[]).
stream_empty
Section titled “stream_empty”pub function stream_empty(): Streamstream_empty() — zero-length Stream. Useful as a default
/ placeholder.
pub function (s: Stream) len(): i32(s: Stream).len() — total byte count of the Stream’s
backing buffer (independent of the read cursor).
remaining
Section titled “remaining”pub function (s: Stream) remaining(): i32(s: Stream).remaining() — bytes between the cursor and
the end of the buffer. Zero when the Stream is fully
consumed.
is_empty
Section titled “is_empty”pub function (s: Stream) is_empty(): boolean(s: Stream).is_empty() — whether the Stream has any
unread bytes left. The dual of .remaining() == 0;
reads better at call sites that gate on “any more data?”
read_all
Section titled “read_all”pub function (s: Stream) read_all(): (u8[], Stream)(s: Stream).read_all() — consume the remaining bytes
as a fresh u8[], returning (bytes, advancedStream) per
the cursor idiom (docs/CURSOR-IDIOM.md). The returned
Stream’s cursor is at the end of the buffer; rebind it:
var (bytes, s) = s.read_all();.
Phase 2 will fold an IoError into the result once host- side reads can fail; Phase 1’s in-memory buffer can’t fail so the bare bytes return is fine.
read_all_string
Section titled “read_all_string”pub function (s: Stream) read_all_string(): (string, Stream)(s: Stream).read_all_string() — consume the remaining
bytes as a UTF-8 string, returning (string, advancedStream).
Convenience over string_from_bytes on read_all’s bytes.
Non-UTF-8 input round-trips through the string as raw bytes
(lang’s string doesn’t enforce UTF-8 validity today).
read_byte
Section titled “read_byte”pub function (s: Stream) read_byte(): (Option[i32], Stream)(s: Stream).read_byte() — read a single byte from the
cursor. Returns (Option[i32], advancedStream): Some(b)
- a Stream advanced past it, or None + the unchanged
Stream when exhausted. Rebind:
var (b, s) = s.read_byte();.
read_n
Section titled “read_n”pub function (s: Stream) read_n(n: i32): (u8[], Stream)(s: Stream).read_n(n) — read up to n bytes from the
cursor, returning (bytes, advancedStream). The byte array
holds the actual bytes consumed (possibly fewer than n at
EOF); empty when already exhausted or n <= 0.
read_line
Section titled “read_line”pub function (s: Stream) read_line(): (Option[string], Stream)(s: Stream).read_line() — read up to and including the
next \n, returning (Option[string], advancedStream).
The line excludes the trailing newline; a trailing \r
(Windows line endings) is also stripped. None + unchanged
Stream when exhausted at the start of the call (EOF); a
final unterminated line returns Some(line) + the advanced
Stream, then None on the subsequent call.