lib: complete the parallel vstream surface to Hare value-return shape (#94 fold-eFinal prep)

The #94 Option-C vstream surface was left incomplete and structurally
divergent from Hare: constructors heap-allocated and returned (X | nomem)
or used out-params instead of Hare's by-value stack ownership; memio lacked
reset/buffer/borrowedread; bufio's scanner was never ported to the vtable.
This is the additive half of the eFinal collapse — OLD surface stays fully
live; the destructive FLIP (delete OLD + drop _v + repoint) is the next
commit.

Reshape all constructors to VALUE-RETURN (field-by-field sret; the heap +
nomem was an unnecessary crutch — wide slice-bearing struct return-by-value
is byte-id-proven, cf 925_sret_struct_return_run). memio fixed/dynamic/
dynamicfrom, bufio init, log new now return the struct by value; the nomem
is gone with the alloc that forced it.

memio: unify the per-flavour ctx structs onto one `stream` (vt at offset 0);
collapse fixed_string + dynamic_string into a single string() over the common
header (bare-str return is the ratified rule-9 frombytes carve-out, cited at
the site per ref/hare/memio/stream.ha:81); port reset/buffer/borrowedread as
single fns over the header.

bufio: collapse the EXISTING scanner subset (newscannerbuf/scanbyte/scanbytes/
scanline/finish + setflush/flush/unread/isbuffered) onto the vtable, with src
now io.vstream so reads go through io.st_read. The Hare scanner functions ww
never implemented (scanrune/scanstring-arbitrary-delim/readtok/readline/
auto-grow newscanner) are out of scope and deferred to #217 — eFinal is a
collapse, not a feature expansion.

Keep the explicit (&fn): *io.T casts on vtable-slot stores (cgen-neutral;
avoids the #214 (X|void) over-acceptance surface; dropping the casts is a
deferred #206 payoff gated on #214).

Self-gate: 776 (memio) 18/18 and 778 (bufio) 27/27, every row carrying a
cs.s == ww.s byte-id check — bufio/fmt/log are not compiler-embedded, so
these rows are their only byte-id coverage. 779/781 stay STAGE_CS-only
pending #209. Regen w6c+wwdump combined.ww (io+memio are the embedded
modules).
This commit is contained in:
2026-05-29 21:14:39 +09:00
parent f9f83faca7
commit 10cb835f99
10 changed files with 1068 additions and 860 deletions

View File

@@ -220,15 +220,21 @@ fn silentprintfln_v(l: *vlogger, format: str, fields: fmt.field...) void = { };
// ---- public API (10 _v variants) -----------------------------------------
// new_v — wire `sl` as a vstdlogger over `sink`. Hare returns by
// value (ref/hare/log/logger.ha:20); ww cgen can't return wide
// structs, so we take an out-parameter pointer (same shape as OLD
// new at log.ww:193 + memio.fixed + bufio.init).
export fn new_v(sl: *vstdlogger, sink: io.vstream) void = {
// new_v — build a vstdlogger over `sink`, returned BY VALUE (fold-eFinal
// PREP). Hare returns the stdlogger by value (ref/hare/log/logger.ha:20);
// the OLD out-parameter shape existed only because wide-struct sret was
// unimplemented — it now round-trips (test/wcc/925), so the constructor
// builds in a local and `return r;` (proven field-by-field sret form).
// vstdlogger is 24B (two fn-ptrs + sink), returned via the SysV memory
// class; the caller owns the returned logger (stack ownership, no-GC)
// and passes `&sl.logger` to the dispatch fns.
export fn new_v(sink: io.vstream) vstdlogger = {
ensureinit_v();
sl.logger.println_v = stdprintln_v;
sl.logger.printfln_v = stdprintfln_v;
sl.sink = sink;
let r: vstdlogger;
r.logger.println_v = stdprintln_v;
r.logger.printfln_v = stdprintfln_v;
r.sink = sink;
return r;
};
// lprintln_v — dispatch `args` through `log`. Mirrors OLD lprintln