Repository navigation
[campaign #239] STEP 4-A — STDLIB FILL II: raw binary I/O (Bytes constructor + LE getters/setters) #326
Description
Part of #239, follow-up to #242 (STEP 3) and pre-req for #243 (STEP 4 per-repo ports).
Why this is needed
The STEP 4 triage on #243 (2026-05-31) found that every estate test repo carrying a binary-layout ABI contract — raze-tui (6 files, 1643L), eventual tree-sitter-k9 / tree-sitter-a2ml ports, half of bofig — builds its test fixtures with:
const buf = new ArrayBuffer(16);
const view = new DataView(buf);
view.setInt32(0, kind, true); // LE
view.setUint16(10, mouse_x, true); // LE
view.setUint8(8, modifiers);
return new Uint8Array(buf);and parses with the symmetric getInt32(0, true) / getUint16(10, true) / getUint8(8).
#242 / affinescript#504 added the read-only accessors that pure-logic ports of the STEP-2 set needed (bytesLength, bytesByteAt, bytesAsciiSlice). They do NOT cover Bytes construction, per-field write at offset, or multi-byte LE read — which is what binary-ABI tests need.
Required surface
All little-endian (the estate C ABIs are LE-pinned per raze-tui's raze-events.ads + Idris2 Events.idr):
| Extern | Lowers to | Notes |
|---|---|---|
bytes_new(n: Int) -> Bytes |
new Uint8Array(n) |
Zeroed buffer |
bytes_fill(n: Int, byte: Int) -> Bytes |
new Uint8Array(n).fill(byte & 0xFF) |
All-byte buffer |
bytes_set_u8(b, offset, v) -> Int |
(new DataView(b.buffer, b.byteOffset, b.byteLength)).setUint8(offset, v & 0xFF), 0 |
Returns 0 |
bytes_set_u16_le(b, offset, v) -> Int |
… .setUint16(offset, v & 0xFFFF, true), 0 |
|
bytes_set_u32_le(b, offset, v) -> Int |
… .setUint32(offset, v >>> 0, true), 0 |
|
bytes_set_i32_le(b, offset, v) -> Int |
… .setInt32(offset, v | 0, true), 0 |
|
bytes_get_u8(b, offset) -> Int |
(new DataView(b.buffer, b.byteOffset, b.byteLength)).getUint8(offset) |
|
bytes_get_u16_le(b, offset) -> Int |
… .getUint16(offset, true) |
|
bytes_get_u32_le(b, offset) -> Int |
… .getUint32(offset, true) |
|
bytes_get_i32_le(b, offset) -> Int |
… .getInt32(offset, true) |
Implementation pattern: same as #504 — extern declarations in stdlib/Deno.affine, lowering table entries in lib/codegen_deno.ml's deno_builtins, smoke test under tests/codegen-deno/.
Out of scope for this issue:
- Big-endian variants (the estate doesn't need them today; revisit if/when an external API forces BE).
- 64-bit getters/setters (
getBigInt64/setBigInt64) — defer to a*_i64_lefollow-up if needed; current STEP 4 candidates max out at 32-bit.
Acceptance
- All 10 externs ship in
stdlib/Deno.affinewith docstrings. tests/codegen-deno/bytes_binary_io.{affine,deno.js,harness.mjs}round-trips a 16-byte raze-tui-shaped record (LE i32 + u32 + u8 + u16 × 2 with explicit pad bytes), with build + parse asserting field-level equality.dune runtestgreen;tools/run_codegen_deno_tests.shgreen.
Refs
- Umbrella: [campaign] TypeScript → AffineScript estate migration (UMBRELLA) #239
- Predecessor: [campaign #239] STEP 3 — STDLIB FILL: discharge gaps surfaced by step 2 #242 (STEP 3) + affinescript#504 (the read-only-Bytes slice)
- Direct unblock: [campaign #239] STEP 4 — TAIL BATCH 2: mid-tier pure-logic repos (4-9 files) #243 (STEP 4) — specifically raze-tui's 6 files
Activity
hyperpolymath commentedon May 31, 2026
PR filed: hyperpolymath/affinescript#507 (auto-merge SQUASH armed). 10 externs in stdlib/Deno.affine + 10 lowerings in lib/codegen_deno.ml + bytes_binary_io test fixture round-trips a raze-tui-shaped 16-byte RazeEvent record (LE i32 + u32 + u8 + u16 × 2) with boundary cases (u32 max, i32 -1, byte-level LE order check via DataView, bytes_fill masking). 353/353 tests green; all codegen-Deno-ESM harnesses pass. Closes this issue on merge.
hyperpolymath commentedon Aug 24, 2026
Closing after stale-open verification: the issue’s implementation PR hyperpolymath/affinescript#507 merged on 2026-06-01. That PR is the stated completion condition for this bounded stdlib slice; the broader migration remains tracked by #239/#243.