Five tags from ref/hare/errors/common.ha — invalid, noaccess, noentry, exists, unsupported — all !void. lib/io keeps eof/closed as plain void (no Hare analogue for ww's singleton-style done) and adds underread. Drops errors.equal/isnil and the old str-sentinel surface.
73 lines
2.2 KiB
Plaintext
73 lines
2.2 KiB
Plaintext
// 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;
|
|
};
|