bufio: bclose flushes only, does not close the underlying (Hare flag::NONE)
This commit is contained in:
@@ -46,8 +46,10 @@
|
||||
// singletons (vtable_r / vtable_w / vtable_rw); ww's vtable always
|
||||
// carries all three callbacks (a zero-length rbuf/wbuf degenerates the
|
||||
// matching callback in-cb). Defer-handle (MANAGED_* ownership bits)
|
||||
// also deferred — caller owns rbuf/wbuf/src; bclose flushes + forwards
|
||||
// close but frees nothing. Both graduate with io fold-2 (#5).
|
||||
// also deferred — caller owns rbuf/wbuf/src; bclose flushes only and
|
||||
// neither frees nor closes (close-propagation rides #5
|
||||
// MANAGED_HANDLE, ref/hare/bufio/stream.ha:194). Both graduate with io
|
||||
// fold-2 (#5).
|
||||
|
||||
package bufio;
|
||||
|
||||
@@ -292,20 +294,15 @@ fn bwrite(s: io.stream, buf: []u8) (size | io.error) = {
|
||||
return buf.len: size;
|
||||
};
|
||||
|
||||
// bclose — flush pending wbuf, forward close to src via io.close.
|
||||
// Caller-owned buffers/src are not freed (drew defer-handle deferral).
|
||||
// bclose — flush pending wbuf only; the underlying src is NOT closed.
|
||||
// Hare's close_buffered closes src solely under flag::MANAGED_HANDLE
|
||||
// (ref/hare/bufio/stream.ha:194); init's default flag::NONE
|
||||
// (stream.ha:73) flushes and leaves src to its owner. Close-propagation
|
||||
// rides the io fold-2 MANAGED_HANDLE machinery (#5), per the ownership
|
||||
// header (bufio.ww:46-50) — caller owns src, bclose frees/closes nothing.
|
||||
fn bclose(s: io.stream) (void | io.error) = {
|
||||
let b: *stream = s: *stream;
|
||||
let fr: (void | io.error) = flush(b);
|
||||
match (fr) {
|
||||
case void => { };
|
||||
case let e: io.error => return e;
|
||||
};
|
||||
let cr: (void | io.error) = io.close(b.src);
|
||||
match (cr) {
|
||||
case void => return void;
|
||||
case let e: io.error => return e;
|
||||
};
|
||||
return flush(b);
|
||||
};
|
||||
|
||||
// ---- scanner (read-ahead tokenizer over an io.stream src) ----------------
|
||||
|
||||
@@ -43,6 +43,27 @@ fn errsource() io.stream = {
|
||||
return &errvt;
|
||||
};
|
||||
|
||||
// ---- a close-recording source for the no-propagate test ---------------
|
||||
//
|
||||
// closevt forwards writes to closesink (so a flush is observable) and
|
||||
// records whether its closer fired in srcclosed.
|
||||
let srcclosed: bool = false;
|
||||
let closevt: io.vtable;
|
||||
let closesink: memio.stream;
|
||||
|
||||
fn closewrite(s: io.stream, buf: []u8) (size | io.error) = {
|
||||
return io.write(&closesink.vt, buf);
|
||||
};
|
||||
fn closeclose(s: io.stream) (void | io.error) = {
|
||||
srcclosed = true;
|
||||
return void;
|
||||
};
|
||||
fn closesource() io.stream = {
|
||||
closevt.writer = (&closewrite): *io.writer;
|
||||
closevt.closer = (&closeclose): *io.closer;
|
||||
return &closevt;
|
||||
};
|
||||
|
||||
// ---- scanbyte: drain four bytes through a 2-byte window ---------------
|
||||
|
||||
@test fn scanbytecases() void = {
|
||||
@@ -732,6 +753,47 @@ fn errsource() io.stream = {
|
||||
assert(!(raw[1] != 81u8));
|
||||
};
|
||||
|
||||
// ---- bclose flushes but does NOT close the underlying ----------------
|
||||
//
|
||||
// Hare's close_buffered closes src only under flag::MANAGED_HANDLE
|
||||
// (ref/hare/bufio/stream.ha:194); init's default flag::NONE flushes
|
||||
// only. The close-recording closesource lets us assert both: the
|
||||
// buffered byte reaches the sink (flush) AND the closer never fires.
|
||||
@test fn streamclosenopropagate() void = {
|
||||
srcclosed = false;
|
||||
let raw: [8]u8;
|
||||
closesink = memio.fixed(raw[0:8]);
|
||||
let src: io.stream = closesource();
|
||||
|
||||
let rb: [4]u8;
|
||||
let wb: [4]u8;
|
||||
let b: bufio.stream = bufio.init(src, rb[0:4], wb[0:4]);
|
||||
let nilbs: [1]u8;
|
||||
bufio.setflush(&b, nilbs[0:0]); // suppress the default '\n' detector
|
||||
|
||||
let p: io.stream = &b.vt;
|
||||
let h: [2]u8;
|
||||
h[0] = 80u8; h[1] = 81u8; // "PQ"
|
||||
let r: (size | io.error) = io.write(p, h[0:2]);
|
||||
match (r) {
|
||||
case let n: size => { assert(!(n: i32 != 2)); };
|
||||
case let e: io.error => abort();
|
||||
};
|
||||
assert(!(closesink.pos != 0)); // still buffered
|
||||
|
||||
let cr: (void | io.error) = io.close(p);
|
||||
match (cr) {
|
||||
case void => { };
|
||||
case let e: io.error => abort();
|
||||
};
|
||||
// Flush happened: the 2 buffered bytes reached the sink.
|
||||
assert(!(closesink.pos != 2));
|
||||
assert(!(raw[0] != 80u8));
|
||||
assert(!(raw[1] != 81u8));
|
||||
// But the underlying was NOT closed (Hare flag::NONE default).
|
||||
assert(!srcclosed);
|
||||
};
|
||||
|
||||
// ---- setflush with a custom non-empty byte-set -----------------------
|
||||
|
||||
@test fn streamsetflushcustom() void = {
|
||||
|
||||
Reference in New Issue
Block a user