lib/memio: wire seeker (io.seek dispatch landed; #5-era deferral stale)
io.error grows errors.invalid (ref/hare/io/types.ha:11 spreads ...errors::error, which includes it; Hare's memio seek returns it on out-of-bounds, stream.ha:134-136) — appended last so existing member tags stay put; no exhaustive io.error matches exist in lib. seekfn mirrors ref/hare/memio/stream.ha:122-140 over the flat header, shared by fixed/dynamic/dynamicfrom (Hare wires the same seek into both vtables). The io.off-vs-i64 arithmetic runs on an i64 copy: cstage binop typing is nominal on aliases, wwstage accepts (filed, ww-core #54). 791's stream_seek_unsupported row re-pins st_seek's void-arm on a hand-built seekerless vtable: its old premise (memio wires no seeker) is retired by this commit; memio seek success is pinned by memiotest. w6c/wwdump main.combined.ww regen'd: they embed lib/io + lib/memio (the freshness gates are blind to this — embedded-source discipline); w6a/w6l/ww don't embed io, verified untouched.
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
package memio;
|
||||
|
||||
import bytes;
|
||||
import errors;
|
||||
import io;
|
||||
import memio;
|
||||
import os;
|
||||
@@ -344,6 +345,193 @@ fn putstr(s: str, into: []u8, off: i32) i32 = {
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
// ---- seekcases: SET/CUR/END × in-bounds/OOB over one fixed stream --------
|
||||
|
||||
// Sequential rows over one 8-byte fixed stream; CUR rows depend on the
|
||||
// cursor left by earlier rows. want = resulting pos for valid rows,
|
||||
// -1 = errors.invalid expected. After EVERY row an io.tell readback
|
||||
// checks the cursor against a shadow `pos` — invalid rows must leave
|
||||
// it untouched (ref/hare/memio/stream.ha:122-140 returns before the
|
||||
// pos store).
|
||||
@test fn seekcases() void = {
|
||||
let arr: [8]u8;
|
||||
arr[0]=10u8; arr[1]=11u8; arr[2]=12u8; arr[3]=13u8;
|
||||
arr[4]=14u8; arr[5]=15u8; arr[6]=16u8; arr[7]=17u8;
|
||||
|
||||
// (whence, off, want)
|
||||
let wh: [12]i32; // 0 SET / 1 CUR / 2 END
|
||||
let off: [12]i64;
|
||||
let want: [12]i64;
|
||||
wh[0] =0; off[0] =3; want[0] =3; // SET forward
|
||||
wh[1] =1; off[1] =2; want[1] =5; // CUR forward
|
||||
wh[2] =1; off[2] =-5; want[2] =0; // CUR back to start
|
||||
wh[3] =2; off[3] =0; want[3] =8; // END exact end
|
||||
wh[4] =2; off[4] =-8; want[4] =0; // END back to start
|
||||
wh[5] =0; off[5] =9; want[5] =-1; // SET past end
|
||||
wh[6] =1; off[6] =-1; want[6] =-1; // CUR before start
|
||||
wh[7] =2; off[7] =1; want[7] =-1; // END past end
|
||||
wh[8] =2; off[8] =-9; want[8] =-1; // END before start
|
||||
wh[9] =0; off[9] =8; want[9] =8; // SET end exact
|
||||
wh[10]=1; off[10]=0; want[10]=8; // CUR no-op at end
|
||||
wh[11]=0; off[11]=0; want[11]=0; // SET rewind
|
||||
|
||||
let st: memio.stream = memio.fixed(arr[0:8]);
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let pos: i64 = 0;
|
||||
let i: i32 = 0;
|
||||
for (i < 12) {
|
||||
let w: io.whence = wh[i]: io.whence;
|
||||
let r: (io.off | io.error) = io.seek(s, off[i], w);
|
||||
match (r) {
|
||||
case let o: io.off => {
|
||||
if (want[i] < 0) { fail(); };
|
||||
if ((o: i64) != want[i]) { fail(); };
|
||||
pos = o: i64;
|
||||
};
|
||||
case let e: io.error => {
|
||||
if (want[i] >= 0) { fail(); };
|
||||
match (e) {
|
||||
case errors.invalid => {};
|
||||
case => fail();
|
||||
};
|
||||
};
|
||||
};
|
||||
let t: (io.off | io.error) = io.tell(s);
|
||||
match (t) {
|
||||
case let o: io.off => { if ((o: i64) != pos) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
|
||||
// Data readback through the repositioned cursor: SET 5 then read
|
||||
// drains bytes 5..7, then eof.
|
||||
let r: (io.off | io.error) = io.seek(s, 5, io.whence.SET);
|
||||
match (r) {
|
||||
case let o: io.off => { if ((o: i64) != 5) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
let out: [8]u8;
|
||||
let rd: (size | io.eof | io.error) = io.read(s, out[0:8]);
|
||||
match (rd) {
|
||||
case let nz: size => {
|
||||
if (nz: i32 != 3) { fail(); };
|
||||
if (out[0] != 15u8) { fail(); };
|
||||
if (out[2] != 17u8) { fail(); };
|
||||
};
|
||||
case io.eof => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
let rd2: (size | io.eof | io.error) = io.read(s, out[0:8]);
|
||||
match (rd2) {
|
||||
case io.eof => {};
|
||||
case let nz: size => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
};
|
||||
|
||||
// ---- emptyseek: every whence over a 0-length buffer ----------------------
|
||||
|
||||
@test fn emptyseek() void = {
|
||||
let arr: [1]u8;
|
||||
arr[0] = 0u8;
|
||||
let st: memio.stream = memio.fixed(arr[0:0]);
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let wh: [5]i32;
|
||||
let off: [5]i64;
|
||||
let want: [5]i64;
|
||||
wh[0]=0; off[0]=0; want[0]=0; // SET 0 — only valid target
|
||||
wh[1]=2; off[1]=0; want[1]=0; // END 0 == start
|
||||
wh[2]=0; off[2]=1; want[2]=-1;
|
||||
wh[3]=1; off[3]=-1; want[3]=-1;
|
||||
wh[4]=2; off[4]=-1; want[4]=-1;
|
||||
|
||||
let i: i32 = 0;
|
||||
for (i < 5) {
|
||||
let w: io.whence = wh[i]: io.whence;
|
||||
let r: (io.off | io.error) = io.seek(s, off[i], w);
|
||||
match (r) {
|
||||
case let o: io.off => {
|
||||
if (want[i] < 0) { fail(); };
|
||||
if ((o: i64) != want[i]) { fail(); };
|
||||
};
|
||||
case let e: io.error => {
|
||||
if (want[i] >= 0) { fail(); };
|
||||
match (e) {
|
||||
case errors.invalid => {};
|
||||
case => fail();
|
||||
};
|
||||
};
|
||||
};
|
||||
i += 1;
|
||||
};
|
||||
};
|
||||
|
||||
// ---- dynamicseek: rewind-and-reread over written data --------------------
|
||||
|
||||
// The dynamic vtable wires the same seekfn; bounds run against the
|
||||
// LOGICAL length (m.len), not capacity (Hare: len(s.buf),
|
||||
// ref/hare/memio/stream.ha:131,136).
|
||||
@test fn dynamicseek() void = {
|
||||
let st: memio.stream = memio.dynamic();
|
||||
let s: io.stream = &st.vt;
|
||||
|
||||
let src: [5]u8;
|
||||
src[0]=30u8; src[1]=31u8; src[2]=32u8; src[3]=33u8; src[4]=34u8;
|
||||
let wr: (size | io.error) = io.write(s, src[0:5]);
|
||||
match (wr) {
|
||||
case let n: size => { if (n: i32 != 5) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
|
||||
// END 0 → 5 (logical length); cap is 8 post-grow, so END 1 must
|
||||
// still be invalid even though capacity would fit it.
|
||||
let r: (io.off | io.error) = io.seek(s, 0, io.whence.END);
|
||||
match (r) {
|
||||
case let o: io.off => { if ((o: i64) != 5) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
let r1: (io.off | io.error) = io.seek(s, 1, io.whence.END);
|
||||
match (r1) {
|
||||
case let o: io.off => fail();
|
||||
case let e: io.error => {
|
||||
match (e) {
|
||||
case errors.invalid => {};
|
||||
case => fail();
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
// CUR -2 → 3; read drains 33,34 then eof.
|
||||
let r2: (io.off | io.error) = io.seek(s, -2, io.whence.CUR);
|
||||
match (r2) {
|
||||
case let o: io.off => { if ((o: i64) != 3) { fail(); }; };
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
let out: [4]u8;
|
||||
let rd: (size | io.eof | io.error) = io.read(s, out[0:4]);
|
||||
match (rd) {
|
||||
case let nz: size => {
|
||||
if (nz: i32 != 2) { fail(); };
|
||||
if (out[0] != 33u8) { fail(); };
|
||||
if (out[1] != 34u8) { fail(); };
|
||||
};
|
||||
case io.eof => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
let rd2: (size | io.eof | io.error) = io.read(s, out[0:4]);
|
||||
match (rd2) {
|
||||
case io.eof => {};
|
||||
case let nz: size => fail();
|
||||
case let e: io.error => fail();
|
||||
};
|
||||
|
||||
let c: (void | io.error) = io.close(s);
|
||||
match (c) { case void => {}; case let e: io.error => fail(); };
|
||||
};
|
||||
|
||||
export fn main() i32 = {
|
||||
signalled = 1; fixedread();
|
||||
signalled = 2; fixedwritecases();
|
||||
@@ -352,5 +540,8 @@ export fn main() i32 = {
|
||||
signalled = 5; borrowedreadcases();
|
||||
signalled = 6; stringview();
|
||||
signalled = 7; dynamicfromseed();
|
||||
signalled = 8; seekcases();
|
||||
signalled = 9; emptyseek();
|
||||
signalled = 10; dynamicseek();
|
||||
return 0;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user