Skip to content

Commit 2adf260

Browse files
committed
refactor(tw): extract Tw_section.Encode.ownership; delete orphan tw_ownership_section.ml
Establishes lib/tw_section.{ml,mli} as the canonical home for typed-wasm custom-section wire encoders, sized to absorb proposal 0001's two new sections (typedwasm.regions, typedwasm.capabilities) when they land. Changes: - lib/tw_section.ml{,i} created. Encode.ownership operates on pre-byte-encoded triples ((int * int list * int) list) — avoids a Codegen→Tw_section→Codegen type cycle while keeping the byte layout intact. - lib/codegen.ml:159-177 — build_ownership_section body replaced with a 6-line wrapper that maps ownership_kind→byte and delegates to Tw_section.Encode.ownership. Same signature, byte-equal output. - lib/dune — tw_section module added. - lib/tw_ownership_section.ml DELETED. Was orphan: not in lib/dune modules list, no callers, only string-mentioned in tw_verify.ml's stale doc comment (which is also fixed here). - lib/tw_verify.ml:213 — stale doc comment updated: Tw_ownership_section.build_section → Tw_section.Encode.ownership. Rationale: #444 — prevent the 3-sections × 2-copies = 6-encoder fan-out when proposal 0001 (hyperpolymath/typed-wasm#34, hyperpolymath/typed-wasm#76) lands. Sharing the internal LE writers (write_u32_le / write_u8) inside Tw_section.Encode means future Encode.regions / Encode.capabilities land in one place rather than duplicating the buffer plumbing. ADR-021 v2-emit flip is OUT OF SCOPE. Tw_section.Encode.ownership ships v1. When the cross-repo coordination unblocks, the flip is a localised change to this one module. Tea_* hand-rolled fixture encoders (lib/tea_bridge.ml, lib/tea_cs_bridge.ml, lib/tea_router.ml) are intentionally NOT migrated in this PR — they hard-code demo bytes for tea demonstrations, which is a separate concern from the live producer-side dedup. Verification: dune build clean; dune runtest 352/352 passing (round-trip tests would catch any byte divergence). Refs #444 Refs hyperpolymath/typed-wasm#34 Refs hyperpolymath/typed-wasm#76
1 parent 9b9b321 commit 2adf260

6 files changed

Lines changed: 69 additions & 115 deletions

File tree

lib/codegen.ml

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -157,24 +157,12 @@ let ownership_kind_byte = function
157157
u8* param_kind (one per param, see kind encoding above)
158158
u8 return_kind *)
159159
let build_ownership_section (annots : (int * ownership_kind list * ownership_kind) list) : bytes =
160-
if annots = [] then Bytes.empty
161-
else
162-
let buf = Buffer.create 64 in
163-
let write_u32_le n =
164-
Buffer.add_char buf (Char.chr (n land 0xff));
165-
Buffer.add_char buf (Char.chr ((n lsr 8) land 0xff));
166-
Buffer.add_char buf (Char.chr ((n lsr 16) land 0xff));
167-
Buffer.add_char buf (Char.chr ((n lsr 24) land 0xff))
168-
in
169-
let write_u8 n = Buffer.add_char buf (Char.chr (n land 0xff)) in
170-
write_u32_le (List.length annots);
171-
List.iter (fun (func_idx, param_kinds, ret_kind) ->
172-
write_u32_le func_idx;
173-
write_u8 (List.length param_kinds);
174-
List.iter (fun k -> write_u8 (ownership_kind_byte k)) param_kinds;
175-
write_u8 (ownership_kind_byte ret_kind)
176-
) annots;
177-
Buffer.to_bytes buf
160+
Tw_section.Encode.ownership
161+
(List.map (fun (func_idx, param_kinds, ret_kind) ->
162+
(func_idx,
163+
List.map ownership_kind_byte param_kinds,
164+
ownership_kind_byte ret_kind))
165+
annots)
178166

179167
(** Map AffineScript type to WASM value type *)
180168
let type_to_wasm (ty : type_expr) : value_type result =

lib/dune

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
token
8383
trait
8484
tw_interface
85+
tw_section
8586
tw_verify
8687
typecheck
8788
types

lib/tw_ownership_section.ml

Lines changed: 0 additions & 96 deletions
This file was deleted.

lib/tw_section.ml

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
(* SPDX-License-Identifier: MPL-2.0 *)
2+
(* SPDX-FileCopyrightText: 2026 hyperpolymath *)
3+
4+
module Encode = struct
5+
let write_u32_le buf n =
6+
Buffer.add_char buf (Char.chr (n land 0xff));
7+
Buffer.add_char buf (Char.chr ((n lsr 8) land 0xff));
8+
Buffer.add_char buf (Char.chr ((n lsr 16) land 0xff));
9+
Buffer.add_char buf (Char.chr ((n lsr 24) land 0xff))
10+
11+
let write_u8 buf n = Buffer.add_char buf (Char.chr (n land 0xff))
12+
13+
let ownership (annots : (int * int list * int) list) : bytes =
14+
if annots = [] then Bytes.empty
15+
else
16+
let buf = Buffer.create 64 in
17+
write_u32_le buf (List.length annots);
18+
List.iter (fun (func_idx, param_kind_bytes, ret_kind_byte) ->
19+
write_u32_le buf func_idx;
20+
write_u8 buf (List.length param_kind_bytes);
21+
List.iter (fun b -> write_u8 buf b) param_kind_bytes;
22+
write_u8 buf ret_kind_byte
23+
) annots;
24+
Buffer.to_bytes buf
25+
end

lib/tw_section.mli

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
(* SPDX-License-Identifier: MPL-2.0 *)
2+
(* SPDX-FileCopyrightText: 2026 hyperpolymath *)
3+
4+
(** Canonical home for typed-wasm custom-section encoders.
5+
6+
Wire encoders operate on pre-byte-encoded triples to keep this
7+
module free of any dependency on producer-side ownership types
8+
(avoiding a cycle with [Codegen]). Callers map their domain
9+
types to bytes before invoking.
10+
11+
Forward-compatibility slot for typed-wasm proposal 0001 (issue
12+
hyperpolymath/typed-wasm#34): [Encode.regions] and
13+
[Encode.capabilities] land here when the proposal promotes to
14+
[accepted]. Sharing the internal LE writers (u8 / u32le / leb128)
15+
inside this module prevents the 3-sections × 2-copies = 6-encoder
16+
fan-out flagged by hyperpolymath/affinescript#444. *)
17+
18+
module Encode : sig
19+
(** v1 wire format for [typedwasm.ownership]:
20+
u32le entry_count
21+
per entry:
22+
u32le func_index
23+
u8 param_count
24+
u8* param_kind (one per param)
25+
u8 return_kind
26+
27+
Caller responsibilities:
28+
- Map domain ownership type → byte before calling
29+
(see [Codegen.ownership_kind_byte]).
30+
- Empty input → [Bytes.empty]; caller omits the section.
31+
32+
Producer-emit is v1 per ADR-021. Parser-side v2 support lives in
33+
[Tw_verify.parse_ownership_section_payload]; emit-side flip is
34+
cross-repo-coordinated, not local to this function. *)
35+
val ownership : (int * int list * int) list -> bytes
36+
end

lib/tw_verify.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ let verify_module
210210
211211
Per ADR-021's coordinated landing protocol, this verifier ships
212212
parse-support FIRST. AffineScript's emitter ([Codegen.build_ownership_
213-
section] / [Tw_ownership_section.build_section]) stays on v1 until
213+
section] / [Tw_section.Encode.ownership]) stays on v1 until
214214
[hyperpolymath/typed-wasm]'s Rust verifier + [hyperpolymath/ephapax]'s
215215
OCaml verifier also ship parse-support; then all producers flip to v2
216216
emit together. See [docs/specs/TYPED-WASM-COORDINATION-LEDGER.adoc]

0 commit comments

Comments
 (0)