// stream — Hare-shaped vtable port. Project #94 fold-e1. // // Adds the additive vtable surface alongside lib/io/io.ww's pre-vtable // stream struct + read/write/close wrappers (which fold-e2-eN migrate // to vtable-backed implementations and then retire). Three exports: // // vtable a struct of optional fn-pointer slots — reader/writer/ // closer per ref/hare/io/stream.ha:36-42. Hare spells the // nullable as `nullable *T`; ww parser rejects that // spelling (#192), so each slot is a `(*T | void)` tagged // union (Plan-9-lean per the Nullable kept ruling; opt-in // at optionality boundaries only). // vstream `*vtable` alias matching Hare's `stream = *vtable` // (ref/hare/io/stream.ha:33). Named `vstream` rather than // `stream` because lib/io/io.ww still owns the legacy // `stream` struct name until fold-eN collapses both. // st_read / // st_write / // st_close the three dispatchers per ref/hare/io/stream.ha:44-68. // Each `match`es the matching vtable slot, returns // `errors.unsupported` (widened twice) when the slot is // void, otherwise calls through the fn pointer. // // Fold-e1 cgen/checker dependencies (all closed at HEAD): #191 // (N_DOT on aliased-ptr receiver — `s.reader` resolves through the // `vstream = *vtable` alias), #198 (`is` on cross-module variant // tag), #199 α (concrete→tagged widen via NAMED-variant nominal // match, used by `let e: error = u;`), #200 (`as` payload-extract), // #201 (return-of-tagged-call forwards instead of rewinds), #205 // (tagged→tagged subset accepts NAMED-variant nominal match, used // by `return e;` where ret type contains `error` as a direct // variant). Two direct widens compose for the void-arm `return`: // concrete `errors.unsupported` → tagged `error` via #199 α, then // tagged `error` → tagged `(size | eof | error)` via #205. // // Deferrals (drew-signed): `seeker` lands with fold-e2 once `off` // + `whence` plug into the signature; Hare's `?`-propagating // `st_close` body (`c(s)?;`) collapses to a direct `return (*c)(s);` // here because #173 (TRY-on-tagged-return both-stages broken) is // still open — the dispatcher's surface stays Hare-shaped, only the // internal try-prop is omitted. package io; // ref/hare/io/stream.ha:36-42. Nullable spelling per #192 (ww parser // rejects `nullable *T`); each slot is `(*T | void)`. export type vtable = struct { reader: (*reader | void), writer: (*writer | void), closer: (*closer | void), }; // ref/hare/io/stream.ha:33. `vstream` not `stream` while io.ww still // owns the legacy `stream` struct name. export type vstream = *vtable; // ref/hare/io/stream.ha:44-50. The void-arm `return e;` chains two // direct widens: `errors.unsupported → error` via #199 α, then // `error → (size | eof | error)` via #205. The call-arm spells the // fn-ptr call explicitly per #193 (ww requires `(*r)(args)` rather // than implicit `r(args)`). export fn st_read(s: vstream, buf: []u8) (size | eof | error) = { match (s.reader) { case void => { let u: errors.unsupported; let e: error = u; return e; }; case let r: *reader => return (*r)(s, buf); }; }; // ref/hare/io/stream.ha:53-59. export fn st_write(s: vstream, buf: []u8) (size | error) = { match (s.writer) { case void => { let u: errors.unsupported; let e: error = u; return e; }; case let w: *writer => return (*w)(s, buf); }; }; // ref/hare/io/stream.ha:62-68. Hare propagates the close error via // `c(s)?;` then falls through to the void arm; ww collapses to a // direct return because #173 (TRY-on-tagged-return) is still open. // The surface (void | error) matches; only the internal try-prop // is omitted. export fn st_close(s: vstream) (void | error) = { match (s.closer) { case void => return void; case let c: *closer => return (*c)(s); }; };