bufio: preserve partial flush progress

This commit is contained in:
2026-08-09 18:05:21 +09:00
parent cf8244c0ec
commit 09b6f22e85
2 changed files with 123 additions and 23 deletions

View File

@@ -36,6 +36,71 @@ fn closesource() io.stream = {
return &closevt;
};
type failstream = struct {
vt: io.vtable,
out: [16]u8,
pos: i32,
calls: i32,
zero: bool,
};
fn failwrite(s: io.stream, buf: []u8) (size | io.error) = {
let f: *failstream = s: *failstream;
f.calls += 1;
if (f.calls == 2) {
if (f.zero) { return 0: size; };
let nm: nomem;
let e: io.error = nm;
return e;
};
let n: i32 = buf.len;
if (f.calls == 1 && n > 2) { n = 2; };
let i: i32 = 0;
for (i < n) {
f.out[f.pos + i] = buf[i];
i += 1;
};
f.pos += n;
return n: size;
};
fn checkpartialflush(zero: bool) void = {
let sink: failstream;
sink.vt.writer = (&failwrite): *io.writer;
sink.pos = 0;
sink.calls = 0;
sink.zero = zero;
let rb: [1]u8;
let wb: [4]u8;
let b: bufio.stream = bufio.init(&sink.vt, rb[0:1], wb[0:4]);
let src: [4]u8;
let _: i32 = sputstr("ABCD", src[0:4], 0);
let wr: (size | io.error) = io.write(&b.vt, src[0:4]);
match (wr) { case let n: size => {}; case let e: io.error => abort(); };
let first: (void | io.error) = bufio.flush(&b);
match (first) {
case void => abort();
case let e: io.error => assert(e is nomem);
};
assert(sink.pos == 2);
assert(b.wend == 2);
assert(wb[0] == 'C' && wb[1] == 'D');
let second: (void | io.error) = bufio.flush(&b);
match (second) { case void => {}; case let e: io.error => abort(); };
assert(b.wend == 0);
assert(sink.pos == 4);
assert(sink.out[0] == 'A' && sink.out[1] == 'B');
assert(sink.out[2] == 'C' && sink.out[3] == 'D');
};
@test fn streampartialflusherror() void = {
checkpartialflush(false);
};
@test fn streampartialflushzero() void = {
checkpartialflush(true);
};
@test fn streamsmallwrite() void = {
let raw: [16]u8;
let mem: memio.stream = memio.fixed(raw[0:16]);
@@ -313,6 +378,24 @@ fn closesource() io.stream = {
assert(!(out[3] != 71u8)); // 'G'
};
@test fn streamunreadoverlap() void = {
let raw: [1]u8;
let mem: memio.stream = memio.fixed(raw[0:0]);
let rb: [4]u8;
let _: i32 = sputstr("ABCD", rb[0:4], 0);
let wb: [1]u8;
let b: bufio.stream = bufio.init(&mem.vt, rb[0:4], wb[0:1]);
bufio.unread(&b, rb[0:3]);
let out: [3]u8;
let r: (size | io.eof | io.error) = io.read(&b.vt, out[0:3]);
match (r) {
case let n: size => assert(n: i32 == 3);
case io.eof => abort();
case let e: io.error => abort();
};
assert(out[0] == 'A' && out[1] == 'B' && out[2] == 'C');
};
@test fn streamscannerunread() void = {
let raw: [16]u8;
let n: i32 = sputstr("hello\n", raw[0:16], 0);