Parent: #140
Tracked by: #134, #163, #164
Follow-up to: #199
Pinned scope
Implement the three remaining external-string exports shared by the pinned Home 7ed99c02 and Bun 4982b91e private profiles:
ZigString__external — retain the caller buffer and invoke (ctx, ptr, len) exactly once when the JS string releases it.
ZigString__toExternalValueWithCallback — the same exact-once lifetime with the pinned null callback context.
ZigString__toExternalU16 — transfer a globally allocated UTF-16 buffer and preserve exact UTF-16 code units, including lone surrogates.
The pinned references are src/jsc/bindings/bindings.cpp plus src/jsc/ZigString.zig/ZigString.rs. Copied, atomic, and rope construction are already complete under #199.
Design requirements
- External storage stays immutable and usable until the last engine reference dies; do not implement a copy followed by an eager callback and call it external ownership.
- Finalization is exact-once across ordinary GC, duplicate references, context teardown, construction failure, and zero-length strings.
- Callback execution must be thread-safe, must not occur while GC/object locks are held, and must preserve the supplied pointer, length, and context exactly.
- Latin-1/tagged UTF-16 decoding and UTF-16/WTF-8 conversion preserve JavaScript code-unit semantics, including astral pairs and lone surrogates.
- Invalid pointer/length pairs, over-limit lengths, cross-VM misuse, and allocation failure publish the correct pending exception while returning the empty encoded sentinel and releasing transferred ownership exactly once where required.
- Arena and moving-GC modes have one documented ownership model; if zig-gc needs a general external-cell finalizer hook, implement and test it in
~/Code/Libraries/zig-gc as its own linked small commit.
Acceptance
- Focused Zig tests cover 8-bit and 16-bit buffers, empty strings, embedded NUL, astral/lone-surrogate values, source lifetime, mutation visibility contract, duplicate references, collection, teardown, callback reentry, callback thread behavior, errors, and injected OOM.
- The separately compiled Home consumer declares, links, and executes all three signatures.
- Home and Bun inventories and ABI documentation are regenerated with exact counts.
- Relevant focused tests and both ABI audits pass; one full CI run is accepted before closure.
- Parent issues receive completion evidence and updated remaining counts.
Parent: #140
Tracked by: #134, #163, #164
Follow-up to: #199
Pinned scope
Implement the three remaining external-string exports shared by the pinned Home
7ed99c02and Bun4982b91eprivate profiles:ZigString__external— retain the caller buffer and invoke(ctx, ptr, len)exactly once when the JS string releases it.ZigString__toExternalValueWithCallback— the same exact-once lifetime with the pinned null callback context.ZigString__toExternalU16— transfer a globally allocated UTF-16 buffer and preserve exact UTF-16 code units, including lone surrogates.The pinned references are
src/jsc/bindings/bindings.cppplussrc/jsc/ZigString.zig/ZigString.rs. Copied, atomic, and rope construction are already complete under #199.Design requirements
~/Code/Libraries/zig-gcas its own linked small commit.Acceptance