nx_readcap_lib.nx source
↩ module page · 84 lines · 4187 B
1// nx_readcap_lib.nx -- THE ONE read-into-a-caller's-cap helper (dataio DI16, first cause, 2026-09-06).
2//
3// MEASURED before this lib existed: the io-envelope census worklist held 1,082 silent readers in 803 files, and its
4// SHAPES table showed the top of the population was ONE helper family copied by hand -- `sys_read(fd, buf+n, cap-n)`
5// in a loop that stops when the cap fills and never says so (x28, x22, x20, x19, x15, x13 ...). Every copy is a
6// silent-truncation cap: the caller cannot tell "the file was exactly cap bytes" from "the cap filled and the tail
7// is gone". This lib is the bus stop: ONE loop, ONE named state per outcome, so a consumer that adopts it has no
8// sys_read( site of its own and the census counts it CONVERTED.
9//
10// States (rc_fill): RC_EOF the source ended before the cap (buf holds all of it) / RC_CAPPED the cap filled and the
11// source was NOT probed further (a socket must not be probed: the next byte may never come) / RC_ERR a read failed
12// (st[1] = the rc). rc_read_file_into adds the file-only refinement: after a CAPPED fill it reads ONE more byte, so
13// RC_FULL means "TRUNCATED, more remains" and RC_EXACT means "the file was exactly cap bytes" -- the distinction the
14// hand-rolled loops could never make. rc_state_name spells the TRUNCATED state so any consumer that prints it
15// announces its envelope in the census's own vocabulary.
16//
17// Whole-file reads with no cap at all belong to sys_read_file (nx_syscalls), which sizes from the file; this lib is
18// for the case where the BUFFER is the caller's and the cap is real (a fixed header, a bounded request line, a window).
19// license_tier: ORIGINAL No hw writes (Rule 26).
20import "nx_syscalls.nx"
21
22const RC_EOF: i64 = 0
23const RC_CAPPED: i64 = 1
24const RC_FULL: i64 = 2
25const RC_EXACT: i64 = 3
26const RC_ERR: i64 = 4
27const RC_PROBE_BYTES: i64 = 1 // one byte decides EXACT vs FULL; a bigger probe would only cost more and prove no more
28
29// fill buf[0..cap) from fd until EOF or the cap. Returns bytes read (>= 0). st[0] = RC_EOF | RC_CAPPED | RC_ERR;
30// st[1] = the failing read's rc, else 0. Never reads past cap, never probes: safe on sockets and pipes.
31func rc_fill(fd: i64, buf: *u8, cap: i64, st: *i64) -> i64 {
32 var got: i64 = 0
33 st[0] = RC_EOF
34 st[1] = 0
35 var go: i64 = 1
36 while go == 1 {
37 if got >= cap { go = 0 } else {
38 let r: i64 = sys_read(fd, ((buf as i64) + got) as *u8, cap - got)
39 if r < 0 { st[0] = RC_ERR; st[1] = r; return got }
40 if r == 0 { go = 0 } else { got = got + r }
41 }
42 }
43 if got >= cap { st[0] = RC_CAPPED }
44 return got
45}
46
47// the file-only refinement: a CAPPED fill is followed by ONE probe read, so the caller learns whether the file was
48// exactly cap bytes (RC_EXACT) or the cap truncated it (RC_FULL, more remains). st[2] receives the probe rc.
49func rc_fill_file(fd: i64, buf: *u8, cap: i64, st: *i64) -> i64 {
50 let n: i64 = rc_fill(fd, buf, cap, st)
51 st[2] = 0
52 if st[0] == RC_CAPPED {
53 let probe: *u8 = sys_mmap(16)
54 let p: i64 = sys_read(fd, probe, RC_PROBE_BYTES)
55 st[2] = p
56 if p > 0 { st[0] = RC_FULL } else { if p == 0 { st[0] = RC_EXACT } else { st[0] = RC_ERR; st[1] = p } }
57 }
58 return n
59}
60
61// open + fill_file + close. A missing or unreadable file is RC_ERR with the open rc in st[1] and 0 bytes.
62func rc_read_file_into(path: *u8, buf: *u8, cap: i64, st: *i64) -> i64 {
63 let fd: i64 = sys_openat_rd(path)
64 if fd < 0 { st[0] = RC_ERR; st[1] = fd; st[2] = 0; return 0 }
65 let n: i64 = rc_fill_file(fd, buf, cap, st)
66 sys_close(fd)
67 return n
68}
69
70// 1 when the read is COMPLETE (EOF or EXACT), 0 when it is not (CAPPED, FULL, ERR) -- the one question a consumer
71// must ask before trusting buf as the whole source
72func rc_complete(st: *i64) -> i64 {
73 if st[0] == RC_EOF { return 1 }
74 if st[0] == RC_EXACT { return 1 }
75 return 0
76}
77
78func rc_state_name(s: i64) -> *u8 {
79 if s == RC_EOF { return "EOF" as *u8 }
80 if s == RC_CAPPED { return "CAPPED-unprobed" as *u8 }
81 if s == RC_FULL { return "TRUNCATED-more-remains" as *u8 }
82 if s == RC_EXACT { return "EXACT" as *u8 }
83 return "ERR" as *u8
84}