lib: collapse the parallel vstream scaffold onto the single Hare io surface (#94 fold-eFinal)
The Option-C parallel _v vstream API was scaffolding to bring the io stack up alongside the old surface; carrying both permanently is a rule-9 divergence from ref/hare, which has exactly one io surface. Collapse onto that surface (stream = *vtable, ref/hare/io/stream.ha) and rename the _v symbols to their Hare names (io vstream->stream, fmt vfprint->fprint, bufio/memio/log surfaces, log.new). Deletes the 4 lib/*/vstream.ww scaffold files; regenerates w6c/wwdump combined.ww. cstage and wwstage stay byte-identical and combined_ww_fresh holds; all 220 tests pass.
This commit is contained in:
@@ -3,7 +3,9 @@
|
||||
// Every @test enumerates parallel `[N]T` arrays of inputs and
|
||||
// expectations, then iterates one body across them. Parallel arrays
|
||||
// (rather than `[N]struct{...}`) sidestep the cstage cgen's chained
|
||||
// `arr[i].field` store gap (task #6).
|
||||
// `arr[i].field` store gap (task #6). #94 fold-eFinal: the unified
|
||||
// value-return surface (`let st = memio.fixed(buf); &st.vt` into the
|
||||
// io dispatchers; io.read/write/close return size/io.error).
|
||||
|
||||
package memio;
|
||||
|
||||
@@ -47,9 +49,8 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
req[3]=1; wantn[3]=0; wantf[3]=0u8; wantl[3]=0u8; weof[3]=1;
|
||||
req[4]=0; wantn[4]=0; wantf[4]=0u8; wantl[4]=0u8; weof[4]=1;
|
||||
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.fixed(&mem, &s, arr[0:8]);
|
||||
let st: memio.stream = memio.fixed(arr[0:8]);
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let out: [8]u8;
|
||||
let i: i32 = 0;
|
||||
@@ -58,32 +59,32 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
let k: i32 = 0;
|
||||
for (k < 8) { out[k] = 0u8; k += 1; };
|
||||
|
||||
let r: (i32 | io.eof | io.closed) = io.read(&s, out[0:req[i]]);
|
||||
let r: (size | io.eof | io.error) = io.read(s, out[0:req[i]]);
|
||||
match (r) {
|
||||
case let n: i32 => {
|
||||
case let nz: size => {
|
||||
let n: i32 = nz: i32;
|
||||
if (weof[i] != 0) { fail(); };
|
||||
if (n != wantn[i]) { fail(); };
|
||||
if (n > 0 && out[0] != wantf[i]) { fail(); };
|
||||
if (n > 0 && out[n - 1] != wantl[i]) { fail(); };
|
||||
};
|
||||
case io.eof => { if (weof[i] == 0) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
|
||||
// closenoop on a fixed stream returns void.
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
// fixed stream has no closer → io.close returns void.
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- fixedwritecases: full-fit / exact-fill / partial / overflow -------------
|
||||
|
||||
@test fn fixedwritecases() void = {
|
||||
let dst: [16]u8;
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.fixed(&mem, &s, dst[0:16]);
|
||||
let st: memio.stream = memio.fixed(dst[0:16]);
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
// One flat source; rows index into it via (off, len). Sequence:
|
||||
// "hello " (6), "world!!" (7), "XXXXXXX" (7), "Y" (1).
|
||||
@@ -104,10 +105,10 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
for (i < 4) {
|
||||
let lo: i32 = off[i];
|
||||
let hi: i32 = lo + ln[i];
|
||||
let r: (i32 | io.closed) = io.write(&s, src[lo:hi]);
|
||||
let r: (size | io.error) = io.write(s, src[lo:hi]);
|
||||
match (r) {
|
||||
case let n: i32 => { if (n != wantn[i]) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let n: size => { if (n: i32 != wantn[i]) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
@@ -117,27 +118,23 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
if (!bytes.equal(dst[0:16], want[0:16])) { fail(); };
|
||||
|
||||
// 0-byte write is always 0 with no side effects.
|
||||
let r0: (i32 | io.closed) = io.write(&s, src[0:0]);
|
||||
let r0: (size | io.error) = io.write(s, src[0:0]);
|
||||
match (r0) {
|
||||
case let n: i32 => { if (n != 0) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let n: size => { if (n != 0: size) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- dynamicgrowcases: every cap doubling exercised ---------------------
|
||||
|
||||
// Drive grow 0 → 8 → 16 → 32 by writing sized chunks. Verify
|
||||
// accumulated `pos` after each step. Suffix `cases` mirrors
|
||||
// `fixedwritecases` / `borrowedreadcases`; bare `dynamicgrow`
|
||||
// would collide with memio.ww's private `dynamicgrow` in the same
|
||||
// package.
|
||||
// accumulated `pos` after each step.
|
||||
@test fn dynamicgrowcases() void = {
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.dynamic(&mem, &s);
|
||||
let st: memio.stream = memio.dynamic();
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let src: [32]u8;
|
||||
let _: i32 = putstr("abcdefghijklmnopqrstuvwxyz012345", src[0:32], 0);
|
||||
@@ -157,20 +154,20 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
for (i < 5) {
|
||||
let lo: i32 = off;
|
||||
let hi: i32 = lo + chunk[i];
|
||||
let r: (i32 | io.closed) = io.write(&s, src[lo:hi]);
|
||||
let r: (size | io.error) = io.write(s, src[lo:hi]);
|
||||
match (r) {
|
||||
case let n: i32 => { if (n != chunk[i]) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let n: size => { if (n: i32 != chunk[i]) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
if (memio.buffer(&mem).len != total[i]) { fail(); };
|
||||
if (memio.buffer(&st).len != total[i]) { fail(); };
|
||||
off += chunk[i];
|
||||
i += 1;
|
||||
};
|
||||
|
||||
if (!bytes.equal(memio.buffer(&mem), src[0:26])) { fail(); };
|
||||
if (!bytes.equal(memio.buffer(&st), src[0:26])) { fail(); };
|
||||
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- dynamicreset: write / reset / write cycles -------------------------
|
||||
@@ -178,9 +175,8 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
// op=0 writes `ln` bytes from a rolling source; op=1 resets and ignores
|
||||
// ln. After each row the accumulated len must equal `want`.
|
||||
@test fn dynamicreset() void = {
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.dynamic(&mem, &s);
|
||||
let st: memio.stream = memio.dynamic();
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let src: [16]u8;
|
||||
src[0]=10u8; src[1]=20u8; src[2]=30u8; src[3]=40u8;
|
||||
@@ -200,26 +196,26 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
let i: i32 = 0;
|
||||
for (i < 6) {
|
||||
if (op[i] == 1) {
|
||||
memio.reset(&mem);
|
||||
memio.reset(&st);
|
||||
off = 0;
|
||||
} else {
|
||||
let lo: i32 = off;
|
||||
let hi: i32 = lo + ln[i];
|
||||
let r: (i32 | io.closed) = io.write(&s, src[lo:hi]);
|
||||
let r: (size | io.error) = io.write(s, src[lo:hi]);
|
||||
match (r) {
|
||||
case let n: i32 => { if (n != ln[i]) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let n: size => { if (n: i32 != ln[i]) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
off += ln[i];
|
||||
};
|
||||
if (memio.buffer(&mem).len != want[i]) { fail(); };
|
||||
if (memio.buffer(&st).len != want[i]) { fail(); };
|
||||
i += 1;
|
||||
};
|
||||
|
||||
if (!bytes.equal(memio.buffer(&mem), src[0:8])) { fail(); };
|
||||
if (!bytes.equal(memio.buffer(&st), src[0:8])) { fail(); };
|
||||
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- borrowedread: under / exact / over / 0-byte ------------------------
|
||||
@@ -228,9 +224,7 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
let arr: [6]u8;
|
||||
arr[0]=0u8; arr[1]=1u8; arr[2]=2u8; arr[3]=3u8; arr[4]=4u8; arr[5]=5u8;
|
||||
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.fixed(&mem, &s, arr[0:6]);
|
||||
let st: memio.stream = memio.fixed(arr[0:6]);
|
||||
|
||||
// (amt, wantfirst, wantlast, weof)
|
||||
let amt: [4]i32;
|
||||
@@ -244,7 +238,7 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
|
||||
let i: i32 = 0;
|
||||
for (i < 4) {
|
||||
let r: ([]u8 | io.eof) = memio.borrowedread(&mem, amt[i]);
|
||||
let r: ([]u8 | io.eof) = memio.borrowedread(&st, amt[i]);
|
||||
match (r) {
|
||||
case let v: []u8 => {
|
||||
if (weof[i] != 0) { fail(); };
|
||||
@@ -261,11 +255,10 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
// ---- stringview: len + endpoints track pos across appends ---------------
|
||||
|
||||
@test fn stringview() void = {
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.dynamic(&mem, &s);
|
||||
let st: memio.stream = memio.dynamic();
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
if (memio.string(&mem).len != 0) { fail(); };
|
||||
if (memio.string(&st).len != 0) { fail(); };
|
||||
|
||||
let src: [32]u8;
|
||||
let _: i32 = putstr("hello world!!", src[0:32], 0);
|
||||
@@ -284,17 +277,17 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
for (i < 3) {
|
||||
let lo: i32 = off[i];
|
||||
let hi: i32 = lo + ln[i];
|
||||
let r: (i32 | io.closed) = io.write(&s, src[lo:hi]);
|
||||
match (r) { case let n: i32 => {}; case io.closed => fail(); };
|
||||
let v: str = memio.string(&mem);
|
||||
let r: (size | io.error) = io.write(s, src[lo:hi]);
|
||||
match (r) { case let n: size => {}; case let e: io.error => fail(); };
|
||||
let v: str = memio.string(&st);
|
||||
if (v.len != want[i]) { fail(); };
|
||||
if (v[0] != wf[i]) { fail(); };
|
||||
if (v[v.len - 1] != wl[i]) { fail(); };
|
||||
i += 1;
|
||||
};
|
||||
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- dynamicfromseed: ownership-transferred seed, read then write -------
|
||||
@@ -302,15 +295,13 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
@test fn dynamicfromseed() void = {
|
||||
// Build a heap-allocated seed via append (rt_ensure path), then
|
||||
// hand ownership to memio. dynamicclose then frees `seed.cap`
|
||||
// bytes — the regression that motivated the `m.cap = buf.cap`
|
||||
// fix in lib/memio/memio.ww.
|
||||
// bytes — the regression that motivated the `cap = buf.cap` fix.
|
||||
let seed: []u8;
|
||||
seed.ptr = nil; seed.len = 0; seed.cap = 0;
|
||||
append(seed, 100u8, 101u8, 102u8, 103u8);
|
||||
|
||||
let mem: memio.state;
|
||||
let s: io.stream;
|
||||
memio.dynamicfrom(&mem, &s, seed);
|
||||
let st: memio.stream = memio.dynamicfrom(seed);
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
// (readn, wantbyte, weof)
|
||||
let rn: [5]i32;
|
||||
@@ -325,15 +316,16 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
let out: [4]u8;
|
||||
let i: i32 = 0;
|
||||
for (i < 5) {
|
||||
let r: (i32 | io.eof | io.closed) = io.read(&s, out[0:rn[i]]);
|
||||
let r: (size | io.eof | io.error) = io.read(s, out[0:rn[i]]);
|
||||
match (r) {
|
||||
case let n: i32 => {
|
||||
case let nz: size => {
|
||||
let n: i32 = nz: i32;
|
||||
if (weof[i] != 0) { fail(); };
|
||||
if (n != rn[i]) { fail(); };
|
||||
if (out[0] != want[i]) { fail(); };
|
||||
};
|
||||
case io.eof => { if (weof[i] == 0) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
@@ -342,14 +334,14 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
// must free the (post-grow) cap, not the seed cap.
|
||||
let extra: [4]u8;
|
||||
extra[0]=200u8; extra[1]=201u8; extra[2]=202u8; extra[3]=203u8;
|
||||
let w: (i32 | io.closed) = io.write(&s, extra[0:4]);
|
||||
let w: (size | io.error) = io.write(s, extra[0:4]);
|
||||
match (w) {
|
||||
case let n: i32 => { if (n != 4) { fail(); }; };
|
||||
case io.closed => fail();
|
||||
case let n: size => { if (n: i32 != 4) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
|
||||
let c: (void | io.closed) = io.close(&s);
|
||||
match (c) { case void => {}; case io.closed => fail(); };
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
|
||||
Reference in New Issue
Block a user