Skip to content

[campaign #239] STEP 4-A — STDLIB FILL II: raw binary I/O (Bytes constructor + LE getters/setters) #326

@hyperpolymath

Description

@hyperpolymath

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_le follow-up if needed; current STEP 4 candidates max out at 32-bit.

Acceptance

  • All 10 externs ship in stdlib/Deno.affine with 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 runtest green; tools/run_codegen_deno_tests.sh green.

Refs

Metadata

Metadata

Assignees

No one assigned

    Labels

    campaignMulti-PR multi-session estate campaignts-to-affinescriptTypeScript→AffineScript migration campaign 2026-05-28

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions