bufio: bread tops up a partial buffer (Hare short-read)

This commit is contained in:
2026-06-15 02:08:55 +09:00
parent 9fcb3be541
commit 9c10a731b0
2 changed files with 106 additions and 9 deletions

View File

@@ -192,25 +192,39 @@ export fn isbuffered(s: io.stream) bool = {
// ---- buffered-stream vtable callbacks ------------------------------------
// bread — buffered read. Recover stream via the intrusive cast; refill
// rbuf from src via io.read on empty pending region. Mirrors
// ref/hare/bufio/stream.ha (stream_read).
// bread — buffered read. Recover stream via the intrusive cast; top up
// rbuf from src via io.read whenever the pending region holds fewer
// bytes than requested AND rbuf has spare capacity (Hare's short-read
// refill, ref/hare/bufio/stream.ha:209). The pending bytes shift to the
// front, then io.read fills the tail; EOF is fatal only when nothing is
// pending. Mirrors ref/hare/bufio/stream.ha:205 (stream_read).
fn bread(s: io.stream, buf: []u8) (size | io.eof | io.error) = {
let b: *stream = s: *stream;
// Degenerate read-disabled mode (zero-length rbuf, bufio.ww:87-89);
// ww's contract returns eof where Hare (always given a buffer) would
// serve 0 — a separate concern from the top-up below.
if (b.rbuf.len == 0) {
let e: io.eof; return e;
};
if (b.rstart >= b.rend) {
let avail: i32 = b.rend - b.rstart;
if (avail < buf.len && avail < b.rbuf.len) {
let i: i32 = 0;
for (i < avail) {
b.rbuf[i] = b.rbuf[b.rstart + i];
i += 1;
};
b.rstart = 0;
b.rend = 0;
let r: (size | io.eof | io.error) = io.read(b.src, b.rbuf);
b.rend = avail;
let r: (size | io.eof | io.error) = io.read(b.src, b.rbuf[b.rend:b.rbuf.len]);
match (r) {
case let n: size => { b.rend = n: i32; };
case io.eof => { let e: io.eof; return e; };
case let n: size => { b.rend += n: i32; };
case io.eof => {
if (avail == 0) { let e: io.eof; return e; };
};
case let e: io.error => return e;
};
};
let avail: i32 = b.rend - b.rstart;
avail = b.rend - b.rstart;
let n: i32 = buf.len;
if (avail < n) { n = avail; };
let i: i32 = 0;