// bufio — buffered reader/writer over io.stream. Plan 9 'bio' // analogue, lowered to ww. The buffer is owned by the caller and // passed in at init time; we don't allocate. // // We keep the stream pointer as *void here to avoid a cross-module // type name (the module-import system isn't online yet); a later // revision will replace it with *io.stream once `use` resolves // types from imported modules. type streamp = *void; type buf = struct { s: streamp, data: *u8, cap: i32, r: i32, // read cursor w: i32, // write cursor (for writers) }; export fn init(b: *buf, s: streamp, data: *u8, cap: i32) void = { b.s = s; b.data = data; b.cap = cap; b.r = 0; b.w = 0; }; // readbyte — pop one byte. void variant signals EOF (empty buffer). // Hare name; the (i32 | void) shape is a subset of Hare's full // (u8 | EOF | io::error) — error reporting from the underlying // stream will arrive when bufio actually wires up to io::stream. export fn readbyte(b: *buf) (i32 | void) = { if (b.r < b.w) { let c: u8 = b.data[b.r]; b.r += 1; return c: i32; }; return; }; // Distinct alias so `(str | linerr)` has two variant types the // tagged-union machinery can keep apart at the tag level. The error // variant carries a short description; callers inspect by length. // Placeholder until bufio graduates to io.stream + named-void tags // (eof / closed / underread). type linerr = str; // readline — Hare-style fallible line read (name transliterated from // `read_line`). Drains the buffer up to (but not including) the next // '\n' and advances the cursor past the newline. Returns the line as // a borrowed str on success, or a linerr describing why no line was // available: // - "eof" when the buffer is empty // - "no newline" when the buffer contains data but no '\n' // // The returned str borrows from the underlying buffer; callers must // consume it (or copy) before refilling. export fn readline(b: *buf) (str | linerr) = { if (b.r >= b.w) { return "eof": linerr; }; let i: i32 = b.r; for (i < b.w) { if (b.data[i] == 10u8) { let s: str; s.ptr = b.data + b.r; s.len = i - b.r; b.r = i + 1; return s; }; i += 1; }; return "no newline": linerr; };