From 5c20c407248358198020f0dab6df3ed243444510 Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 12 May 2026 02:14:09 +0900 Subject: [PATCH] io: graduate stream to tagged-union returns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit read → (i32 | eof | closed), write → (i32 | closed), close → (void | closed). `type eof = void` and `type closed = void` are exported as named-void variants — distinct nominal tags despite identical (zero-byte) payloads. No existing callers exercised the eof/closed sentinels (the smoke test mimics the stream pattern with its own local types), so the graduation is purely API shape — no callsite churn. --- lib/io/stream.ww | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/lib/io/stream.ww b/lib/io/stream.ww index b45bc3c3..2653262a 100644 --- a/lib/io/stream.ww +++ b/lib/io/stream.ww @@ -2,27 +2,32 @@ // // No closures, no methods. A `stream` is a struct of function // pointers plus a `ctx: *void`. The error channel is the return -// value of read/write/close. Negative i32 = errno-style code, -// non-negative = bytes transferred. +// value of read/write/close — Hare-shaped tagged unions instead of +// errno-style integer sentinels. + +// eof — read past the end of the stream. NAMED-void so it's a +// distinct variant tag from `void` (which would be "no result yet"). +export type eof = void; + +// closed — operation attempted on a stream that has already been +// closed. NAMED-void; same shape, different tag. +export type closed = void; type stream = struct { ctx: *void, - read: fn(s: *stream, buf: []u8) i32, - write: fn(s: *stream, buf: []u8) i32, - close: fn(s: *stream) i32, + read: fn(s: *stream, buf: []u8) (i32 | eof | closed), + write: fn(s: *stream, buf: []u8) (i32 | closed), + close: fn(s: *stream) (void | closed), }; -def eof: i32 = -1; -def closed: i32 = -2; - -export fn read(s: *stream, buf: []u8) i32 = { +export fn read(s: *stream, buf: []u8) (i32 | eof | closed) = { return s.read(s, buf); }; -export fn write(s: *stream, buf: []u8) i32 = { +export fn write(s: *stream, buf: []u8) (i32 | closed) = { return s.write(s, buf); }; -export fn close(s: *stream) i32 = { +export fn close(s: *stream) (void | closed) = { return s.close(s); };