Files
ww/lib/io/stream.ww
Hojun-Cho aadc6618f0 lib: banner purge + WHY-only comment sweep (rule 8)
Every // ---- section banner dies (132 -> 0): names carry the WHAT.
Narration deleted (filename restatements, run-with lines, what-the-
next-line-does); every ref/hare cite, task cite, divergence, ABI/
layout contract, and ownership qualifier kept (borrowed-view lines
restored where the sweep over-cut). Comment-only proven: all 442
walk-workdir .s and 32 import-probe .s byte-identical before/after;
libbyteid 56-roster all-ID.
2026-08-08 21:10:18 +09:00

184 lines
5.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// stream — Hare-shaped vtable surface. Project #94 fold-eFinal.
//
// The single io stream surface (the fold-eFinal collapse retired the
// pre-vtable `stream` struct + `closed` tag). 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).
// stream `*vtable` alias matching Hare's `stream = *vtable`
// (ref/hare/io/stream.ha:33).
// read /
// write /
// 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. Hare keeps
// these private (`st_read` …) behind a `handle`-typed
// public `read`/`write`/`close`; ww has no `handle` yet
// (io fold-2, #5), so the dispatchers ARE the public
// surface and grow the `handle` match when #5 lands.
//
// Deferrals (drew-signed): `seeker` lands with io fold-2 (#5) once `off`
// + `whence` plug into the signature. Hare's `?`-propagating `close`
// body (`c(s)?;`) collapses to a direct `return (*c)(s);` here because
// the dispatcher's surface stays Hare-shaped; only the internal
// try-prop is omitted (#173 history, now closed — kept direct for the
// void-arm fall-through shape).
package io;
// Q2 layering (ratified): the file-arm of the handle dispatchers routes
// to os.{read,write,close,lseek}; ww `os` plays Hare's `sys` role, so
// `lib/io import os` is the correct direction (os is the import floor).
import os;
// ref/hare/io/stream.ha:36-42. Nullable spelling per #192 (ww parser
// rejects `nullable *T`); each slot is `(*T | void)`. The `seeker` slot
// (4th) lands with io fold-2 (#5); `copier` stays deferred.
export type vtable = struct {
reader: (*reader | void),
writer: (*writer | void),
closer: (*closer | void),
seeker: (*seeker | void),
};
// ref/hare/io/stream.ha:33.
export type stream = *vtable;
// ref/hare/io/stream.ha:44-51. Private stream-arm body behind the
// handle-typed [[read]] (#5). 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)`).
fn st_read(s: stream, 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-60.
fn st_write(s: stream, 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 for the void-arm fall-through shape. The surface
// (void | error) matches.
fn st_close(s: stream) (void | error) = {
match (s.closer) {
case void => return void;
case let c: *closer => return (*c)(s);
};
};
// ref/hare/io/stream.ha:70-77.
fn st_seek(s: stream, off: off, w: whence) (off | error) = {
match (s.seeker) {
case void => {
let u: errors.unsupported;
let e: error = u;
return e;
};
case let sk: *seeker => return (*sk)(s, off, w);
};
};
// ref/hare/io/handle.ha:16-23. The file arm routes to os.read
// directly (the Q2 layering ruling: os stays below io).
export fn read(h: handle, buf: []u8) (size | eof | error) = {
match (h) {
case let fd: file => {
let r: i64 = os.read(fd, buf.ptr, buf.len: u64);
if (r < 0) {
// #199b: faithful errno→io.error needs the ...errors.error spread; see lib/io/types.ww:40
let u: errors.unsupported;
let e: error = u;
return e;
};
if (r == 0) {
let z: eof;
return z;
};
return r: size;
};
case let s: stream => return st_read(s, buf);
};
};
// ref/hare/io/handle.ha:27-36.
export fn write(h: handle, buf: []u8) (size | error) = {
match (h) {
case let fd: file => {
let r: i64 = os.write(fd, buf.ptr, buf.len: u64);
if (r < 0) {
// #199b: faithful errno→io.error needs the ...errors.error spread; see lib/io/types.ww:40
let u: errors.unsupported;
let e: error = u;
return e;
};
return r: size;
};
case let s: stream => return st_write(s, buf);
};
};
// ref/hare/io/handle.ha:44-51. Hare propagates each arm's error via `?`
// then falls through; ww returns directly (matching st_close's shape).
export fn close(h: handle) (void | error) = {
match (h) {
case let fd: file => {
let r: i32 = os.close(fd);
if (r < 0) {
// #199b: faithful errno→io.error needs the ...errors.error spread; see lib/io/types.ww:40
let u: errors.unsupported;
let e: error = u;
return e;
};
return void;
};
case let s: stream => return st_close(s);
};
};
// ref/hare/io/handle.ha:55-62. The io.whence → os.whence cast bridges
// the two enum copies (same SET/CUR/END values); os.lseek owns the
// syscall.
export fn seek(h: handle, off: off, w: whence) (off | error) = {
match (h) {
case let fd: file => {
let r: i64 = os.lseek(fd, off, w: os.whence);
if (r < 0) {
// #199b: faithful errno→io.error needs the ...errors.error spread; see lib/io/types.ww:40
let u: errors.unsupported;
let e: error = u;
return e;
};
return r: off;
};
case let s: stream => return st_seek(s, off, w);
};
};
// ref/hare/io/handle.ha:65-67.
export fn tell(h: handle) (off | error) = {
return seek(h, 0, whence.CUR);
};