Commands and output
Goalchemy compiles programs written in a restricted subset of Go into other languages. Source files are ordinary .go files: they build and run with the Go toolchain, and Goalchemy accepts the subset described in the language specification. Targets are lowered Go, TypeScript for Node.js, Python 3.10+, Java 21, C# for .NET 8, Rust (edition 2021), C17, and experimental Swift 6.4 on Linux x86_64. Run goalchemy features for the current feature matrix.
Install
Section titled “Install”go build -o bin/goalchemy ./cmd/goalchemyThe repository’s go.mod selects the Go 1.27.1 reference toolchain. Source programs must declare go 1.25 or earlier. TypeScript output needs Node.js 22.6 or later, because it runs .ts files directly through Node’s type stripping.
Commands
Section titled “Commands”| Command | Purpose |
|---|---|
goalchemy check [-gate g] [-tags t] [-json] [packages] |
Load, type-check, and validate against the language gate. |
goalchemy compile -target <go|typescript|python|java|csharp|rust|c|swift|ir> -out <dir> [packages] |
Write a complete, runnable target directory. |
goalchemy build [-config goalchemy.yaml] |
Compile every target listed in a project configuration. |
goalchemy run -target <name> [packages] |
Compile to a temporary directory and run the program. |
goalchemy features |
Print supported features and targets. |
goalchemy spec validate / spec generate [-check] / test |
Maintain and verify the runtime contract catalog. |
Project configuration
Section titled “Project configuration”goalchemy build reads goalchemy.yaml from the current directory:
schema_version: 1packages: [./cmd/app] # package patterns, relative to this filetags: [prod] # optional build tagsgate: sequential # sequential (default) or cooperativenames: source # source (default), readable or compact private identifiersname_collisions: rename # under source names: rename (default) or fail on a collisionpause_model: frames # frames (default) or native (Go, TypeScript, Swift, C#, Python, Rust and Java, experimental)line_directives: true # map generated code back to the source (default)targets: go: {out: out/go} typescript: {out: out/ts} python: {out: out/py} java: {out: out/java} csharp: {out: out/cs} rust: {out: out/rs} c: {out: out/c} swift: {out: out/swift}The file uses the same restricted YAML as the contract catalog: no anchors, aliases, or floats, and no unknown keys.
compile, run, and build accept --names=source|readable|compact and
--name-collisions=rename|fail. compile and run default to source names and
do not load goalchemy.yaml; build uses the configuration’s names and
name_collisions unless a flag is explicitly present. The older
--compact-names flag and compact_names: true key still select compact
names; --compact-names=false selects the default.
goalchemy compile -target rust -out out/rust --names=readable .goalchemy run -target python --names=compact .goalchemy build --name-collisions=failcompile, run, and build also accept --pause-model=frames|native
(build overrides pause_model). frames emits suspending functions as
resumable frames. native is implemented by the Go, TypeScript, Swift, C#,
Python, Rust and Java targets.
On Go it emits them as ordinary Go functions that take the current task and
block at pause points; a turn-passing scheduler keeps exactly one task
goroutine running, and a task that blocks hands the turn directly to the next
task in the same FIFO order as frames. On TypeScript it emits async
functions that take the current task as their last parameter and await
their suspending callees; a primitive that blocks the task awaits a promise
that only Goalchemy’s scheduler settles, when it chooses that task next, so
the JavaScript event loop never decides the order. On Swift it emits
async throws functions that take the task first; each task’s body runs as a
Swift task on its owner’s own executor, on the owner thread, and only
Goalchemy’s scheduler resumes a blocked task, so Swift’s cooperative pool
never runs source code. Swift native output needs task executors: on Apple
platforms, macOS 15, iOS 18, tvOS 18, watchOS 11 or visionOS 2 (the generated
package declares these minimums); frames output has no such requirement. On
C# it emits async methods that take the task first and return the
runtime’s own Async/Async<T> types, whose builders never use the .NET
thread pool, SynchronizationContext or TaskScheduler: a blocked task’s
continuation runs only when Goalchemy’s scheduler chooses that task next, on
the owner thread. On Python it emits async def coroutines that take the task
first and await their suspending callees; Goalchemy’s scheduler drives each
task’s coroutine itself with send, and a blocked task’s coroutine resumes
only when the scheduler chooses that task next, so no asyncio event loop is
involved. On Rust, pausing functions become async fn with boxed
.await calls. The existing FIFO scheduler polls their futures on the owner
thread; wakers never dispatch source code. Primitive calls that complete
immediately do not await. Per-task roots retain source values across awaits,
and frame adapters preserve function values, defers and library exports.
Rust keeps frames as its default. See Rust native pausing
for execution limits and validation, and issue #92 for the overall redesign.
On Java it emits ordinary methods that take the task first
and block at pause points, as on Go: each task body runs on its own virtual
thread, exactly one holds the turn, and a task that blocks hands it directly
to the next task Goalchemy’s scheduler chooses. The generated run.sh starts
the JVM with -Xss1g (virtual thread stacks are bounded by the thread stack
size) and one virtual-thread carrier. Output is identical to frames on all
seven. See issue #92.
compile, run, and build accept --line-directives (default on; build
overrides line_directives). With --line-directives=false, generated code
carries no source annotations: Go output has no /*line*/ comments,
TypeScript output has no source map, and the other targets write no .lines
tables. Runtime positions and compiler diagnostics then refer to the
generated files instead of the Go source.
goalchemy compile -target go -out out/go --line-directives=false .Generated control flow
Section titled “Generated control flow”Every target prints structured control flow rebuilt from the IR’s basic
blocks: if/else, loops with while conditions, labelled break and
continue, and short-circuit conditions. Targets without labelled blocks use
goto (Go, C, C#) or a small exit variable (Python). Single-use temporaries
are folded into the expression that uses them when that keeps Go’s evaluation
order. Two cases keep a dispatch over block numbers: a resumable frame
(--pause-model=frames) switches on the block its task resumes at, so a loop
that pauses runs as a dispatch, and an irreducible block graph (not produced
from Go source) is dispatched rather than structured. Swift functions that
cannot pause, defer or recover are plain Swift functions; the others are
frames.
Generated names
Section titled “Generated names”By default (--names=source) generated code keeps the source identifiers of
types, functions, methods, globals and locals, and renames one only on a
collision:
- A top-level name that several source packages declare is qualified with the
package name (
left_New,right_New); other names stay unqualified. - A name that is a reserved word, a predeclared or builtin name, or a name the
target runtime uses unqualified on that target takes a numeric suffix
(
class_2on TypeScript, Python, Java, C# and Swift). - Every target declares a function’s locals in one scope, so a shadowed local
takes a suffix (
total,total_2), as does a local that would hide a top-level name the function may use. - A method becomes
Type_Methodwhere the target needs a top-level function. - Suffixes are assigned deterministically in source order, so output is stable across runs; adding an unrelated colliding name can rename an existing one, and internal names are not stable across compiler versions.
Every compiler-generated identifier, such as the task parameter _t, frame
helpers, temporaries (_4), closures (_fetchTasks_1) and helper functions
(_a_fetchTasks, _z_Task), starts with _, a prefix source names never
keep: a source name starting with _ is renamed (_hidden becomes
x_hidden), and non-ASCII letters are encoded as _u followed by their
hexadecimal code point and _. TypeScript and Java also use names containing
$, which Go identifiers cannot contain. On C, functions and globals have
external linkage, so they keep generated names (_f_fetchTasks,
_g_count) and source names appear as locals.
--name-collisions=fail (or name_collisions: fail) reports each source name
that would be renamed as a GCE009 diagnostic with its position and the
declaration it collides with, instead of emitting code. The program’s entry
point and package initializers are exempt, since the source never names them.
--names=readable decorates every private name with its category and
identity: an internal function for main.Calculate may be named
fn_main_Calculate_2 and a source local count v_count_7. A named Go struct
contributes its package/type stem to the generated representation; when
several named types share an underlying representation, the lexicographically
smallest source name is chosen deterministically. Anonymous aggregates use
shape names such as struct, array, or map. Unnamed parameters, results,
captures, and temporaries use param, result, capture, and temp stems.
--names=compact replaces compiler-private names with shorter identifiers
derived from the same IR identities. Public library function/type/field names,
capability symbols, runtime type strings, and serialized identities retain
their established contracts in every mode; under source names, a private
name that equals a public library name takes a suffix. Native Go embedding and field rules
also remain intact. Go boundary values from dependency packages receive stable
exported Source_<qualified-type>_<ID> aliases, including values nested in
fields and collections.
Public façade names cannot occupy names reserved by their target’s generated
API. These collisions produce a library-boundary diagnostic in every mode,
rather than invalid target code. For example, Rust rejects public structs named
V, LibraryError, or Vec, and exported functions named Some, None, Ok,
or Err; Python rejects exported functions named None, True, or False.
Swift instead renames a colliding public struct or handle with a trailing
underscore (Error becomes Error_), since Swift and Foundation reserve
common type names such as Error, Data and Task. These names remain
usable internally when the source language permits them.
Readable names help inspect generated source; they do not reconstruct Go’s original control flow or replace source maps. Some targets still store values in runtime frames or numeric aggregate slots and identify them through named helpers or slot constants. Runtime support has its own naming conventions, and IR dumps keep their diagnostic identifiers. Internal names are not a stable API across compiler versions. Neither naming mode promises a performance improvement.
Initialization guidance
Section titled “Initialization guidance”Prefer explicit constructors or setup functions for configuration, I/O, key
generation and resource acquisition. They make dependencies, errors and cleanup
visible to callers. Avoid hiding this work in init() or in package-level
variables initialized by calls to setup functions.
Small deterministic initialization remains supported. Goalchemy preserves Go’s
package-variable dependency ordering and init() functions in its central
initialization routine. Splitting generated code into files does not remove
those effects.
In a library, package initialization runs once per call of a function without
handles and once per handle instance, rather than once at process startup, so
an expensive initializer or externally visible side effect repeats. See
package variables in libraries; the legacy
sequential C scalar/string API uses an explicit goalchemy_init() call.
Output
Section titled “Output”Each target directory contains the generated program, the runtime files it needs (one file per runtime function, plus shared representation files), a README.md, and goalchemy.manifest.json. The manifest records the source profile, compiler version, contract IDs, versions, and hashes, and every runtime and generated file. Output is deterministic for the same inputs.
Program declarations are grouped by their original Go package. The manifest’s
source_packages records each included package’s import path, dependencies and
native source files. Shared representations and the central initializer remain
separate from package-owned declarations. Native public entry points and library
imports stay the same; this does not publish a separate native library for every
Go package. Existing identifier prefixes and compact-name behavior are retained.
Each source file has its own diagnostic map where source positions are available. When an output directory is reused successfully, Goalchemy removes obsolete files listed by its previous generated/runtime inventory and preserves unlisted caller files. Failed emission does not clean that inventory. IR-only output does not use native output inventories.
- Go:
main.go,shared.go,pkg_*.go,go.mod,rt/, all in the existing native package. Run withgo run .. Line directives map positions back to the Goalchemy source. - TypeScript: native
pkg_*.tsESM modules and leafshared.ts; sequential output hasmain.ts, while cooperative output adds portableprogram.tsandhost.ts, withmain.tsas its Node wrapper. Source files have individual.ts.mapfiles. Both includert/andpackage.json. Run withnode main.ts, and add--enable-source-mapsfor source positions in stack traces. Cooperativehost.tsexports Promise-basedrunHost(host)with real monotonic time and an explicit portable output/failure adapter; see the bounded lifecycle and executable-global limits. - Python:
main.py, nativepkg_*.pymodules, leaf_shared.py, andrt/(a package). Individual.py.linessidecars map generated lines to Goalchemy source positions. Run withpython3 main.py; Python 3.10 or later is required. Cooperative output exposes synchronousmain.runHost()with monotonic time, a calling-thread owner and cleanup-before-return; see its lifecycle and recursion limits. - Java:
Main.java, source-packagepkg_*.javaholders, leaf_GoalchemySupport.java,rt/,run.sh, and per-file.java.linessidecars (generated lines to source positions). Run withsh run.sh, which compiles the native source inventory withjavacand runs on a Java 21 or later JDK (JAVA_HOMEis honored). Cooperative output also exposesMain.runHost()for an explicit serialized monotonic executable drive that returns after cleanup; see its lifecycle and executable-global limits. - C#:
Main.cs, source-packagepkg_*.csfiles andshared.csdeclaring one native partialGoProgram,rt/,main.csproj,run.sh, and per-file.cs.linessidecars. Run withsh run.sh, which compiles the generated/runtime inventory with the .NET 8 SDK’s C# compiler (DOTNET_ROOTis honored);dotnet runalso works. The project includes additional root source adapters. Cooperative output exposes Task-returningGoProgram.runHost()using a dedicated monotonic owner driver and serialized executable globals; see its lifecycle and managed-recursion limits. - Rust:
src/main.rs(orsrc/lib.rsfor libraries), nativesrc/pkg_*.rsmodules,src/shared.rs,src/rt/,Cargo.toml,run.sh, and per-file.rs.linessidecars. Explicit module paths allow SDK adapters to rename the generated entry file. Run std-only output withsh run.sh(plainrustc) orcargo run --release; native capability output builds with Cargo and maintained dependencies. Cargo compiles explicit native targets; the SDK package helper supplies its full dependency lock. Cooperative output also exposesrun_host() -> Result<(), HostError>, using a serialized dedicated monotonic owner and cleanup-before-return; see Rust lifecycle and stack limits. Values live in a traced heap collected at safepoints; setGOALCHEMY_HEAP_STATS=1to print heap statistics at exit andGOALCHEMY_GC_THRESHOLD=<n>to collect more often. - C:
main.c, package-ownedpkg_*.ctranslation units,shared.c, declaration-onlygoalchemy_internal.h,rt/(gx.hand one.cfile per runtime function),run.sh, and per-file.c.linessidecars. The scripts compile the explicit generated/runtime inventory as separate native units. Run withsh run.sh, which builds withcc -std=c17and links the Boehm-Demers-Weiser collector (bdwgc 8.x with threads):GOALCHEMY_BDWGCmay name an install prefix, otherwisepkg-config bdw-gcor-lgcis used. Programs that uselib/cryptoorlib/httpalso link OpenSSL (-lssl -lcrypto) and, for HTTP, libcurl throughpkg-config libcurl.CC,CFLAGSandLDLIBSare honored, soCC=clang CFLAGS='-fsanitize=address,undefined'builds a sanitized program. - Swift:
main.swift(orGenerated.swiftfor libraries), package-ownedpkg_*.swiftfiles,shared.swiftwith the canonical type table,rt/,run.sh,LICENSE, and per-file.swift.linessidecars. Native scripts and SwiftPM explicitly list sources within one native module. Run withsh run.sh, which builds a native C module and Swift executable. Requires Swift 6.4, OpenSSL 3, zlib, libcurl and pkg-config even for pure-logic programs. Linux x86_64 is the verified baseline; see Swift setup, semantics and public libraries.
Libraries
Section titled “Libraries”Non-main packages can emit value libraries for Go, TypeScript, Java, C#, Python, Rust, C and Swift:
- Go libraries expose copied values and cancellable, serialized calls.
- TypeScript libraries emit portable JavaScript and declarations for Node and browsers.
- Java libraries emit
Generated.java,build.shand a named-package JAR with byte arrays, typed values and cancellable asynchronous operations. Production crypto requires the pinned BC 1.86 dependency alongside JDK 21. - C# libraries emit .NET 8 class libraries with owned values and cancellable asynchronous operations. Crypto and HTTP use .NET built-ins; IEEE CRC32 adds the official Microsoft
System.IO.Hashing8.0.0 NuGet package. - Swift libraries emit a
GoalchemyGeneratedSwiftPM product with typed values, lossless Go strings, and cancellablewait()/asyncvalue()calls. All current Swift packages need OpenSSL 3, zlib and libcurl development files.
Python libraries emit an importable generated module with owned byte/value
boundaries and cancellable sync/async operations. Production crypto uses
maintained cryptography; HTTP uses the standard library. See the adjacent
Python TDF3 package and boundary evidence.
Rust libraries emit owned typed Cargo Result/Future APIs
with serialized source owners and cleanup-before-publication. Native crypto/HTTP
use maintained locked crates; see Rust TDF3 delivery.
Unsupported public value shapes on supported value-library targets fail with GCE007.
Libraries can also return stateful handles: pointers
to exported structs with methods.
Package variables in libraries
Section titled “Package variables in libraries”Package variables in a library do not live for the process, as they do in a Go program. Each call runs against one set of them:
- A call of an exported function that neither receives nor returns a handle or a source stream starts from fresh package variables, runs package initialization, and discards the variables when it returns. Nothing it writes to a package variable is seen by a later call.
- The call that creates a handle starts an instance with fresh package variables. The instance keeps them: each later call on its handles loads them, runs, and saves them, until the last handle is released. Instances never share package variables.
Calls are serialized across the whole library, so this is what makes package variables safe to use from several host threads without locks. State that must outlive a call, such as a cache or a connection, belongs in a handle: a struct returned by pointer from a constructor, or a package variable used by its methods.
The compiler warns (GCW001) when a call of an export without handles writes a
package variable after initialization: it assigns it, or writes through an
index, field or pointer, or calls a pointer method on it. Reads, writes during
package initialization, and writes from handle methods and constructors are not
reported, nor are executables.
var cache = map[string][]byte{}
func Fetch(url string) []byte { if v, ok := cache[url]; ok { return v // never hit: each Fetch call starts with an empty cache } body := download(url) cache[url] = body // warning GCW001 return body}C aggregate or suspending exports emit goalchemy.h, main.c, rt/ and
build.sh, producing libgoalchemy.a. The owned gxc_value API recursively
copies inputs and detaches outputs/errors, preserving explicit byte lengths and
exact integer bits. Calls serialize on a registered source owner with fresh
initialization; consumers need no collector initialization. Native callbacks
use owned data and cancellation signals; completion waits for actual cleanup
and owner joins. Production capabilities require threaded Boehm, OpenSSL 3 and
libcurl. The adjacent C TDF3 delivery
documents typed headers, submit/drive/wake/cancel/take/destroy, buffer releases,
limits and native consumer evidence.
For sequential scalar/string exports, compiling a package other than main for the C target produces goalchemy.h, main.c, rt/, and build.sh, which builds libgoalchemy.a. The host calls goalchemy_init() once, then the exported functions of the root package. Each export is int pkg_Name(params..., results*...): it returns 0 on success and 1 after an unrecovered panic, whose report goalchemy_panic_message() returns. Integers cross as int64_t (uint64_t for uint64 and uint), Booleans as bool, and strings as a pointer and a length. Exported functions must not suspend, and other parameter types are rejected.
When the working directory or a parent has a .toolchains directory holding jdk-* or dotnet, goalchemy run and the test suites use those toolchains.
On Linux x64, scripts/fetch-toolchains.sh installs the versions and verified
archives in toolchains.lock, including bdwgc and the clang used by
tests/sanitize. The sanitizer runner uses that clang with normal address
randomization. scripts/fetch-toolchains.sh llvm installs only clang and its
private libtinfo5 dependency.
Programs write output with Go’s print and println builtins, which go to standard error. An unrecovered panic prints panic: <value> and exits with status 2, as Go does.
What is rejected
Section titled “What is rejected”goalchemy check reports unsupported constructs with stable codes (see diagnostics) and a one-line remedy. Release 0.1 rejects the following:
- generics, floating-point and complex numbers, and
uintptr unsafe, cgo,goto, and range over functions- pointers to slice or array elements, including pointer-receiver calls on elements
- concurrency under the default sequential gate (compile with
-gate cooperative) - imports other than module source and
github.com/eugenioenko/goalchemy/std/...or.../lib/...packages, including the standard library
Goalchemy replaces the standard library with packages from two roots. Both keep the standard names, so code reads as ordinary Go:
github.com/eugenioenko/goalchemy/std/...holds pure-logic packages written once in the Goalchemy subset. The compiler translates them with your program, so they behave identically on every target and need no native dependencies.github.com/eugenioenko/goalchemy/lib/...holds capability packages that reach the host. Each has a native implementation per target, checked against a contract, and some need native dependencies.
The split, and the core runtime layer behind both, is explained in the runtime library reference.
| Import | Provides |
|---|---|
github.com/eugenioenko/goalchemy/std/strings |
Builder, Reader, Split, Join, Fields, Index, Contains, Trim*, Cut, Replace, NewReplacer, ToLower/ToUpper, EqualFold, and more |
github.com/eugenioenko/goalchemy/std/strconv |
Itoa, Atoi, ParseInt/ParseUint/ParseBool, FormatInt/FormatUint/FormatBool/FormatFloat, ParseFloat, Append*, Quote/QuoteRune and their ToASCII forms, CanBackquote, IsPrint, NumError |
github.com/eugenioenko/goalchemy/std/bytes |
Buffer (also an io.Reader, io.ReaderFrom and io.WriterTo), Reader, Equal, Compare, Index, Split, Fields, TrimSpace, and more |
github.com/eugenioenko/goalchemy/std/io |
Reader, Writer, Closer, Seeker, ReaderAt, WriterAt, ReaderFrom, WriterTo and their compositions, EOF and the other Err* values, Seek* constants, Copy/CopyN/CopyBuffer, ReadAll, ReadFull, ReadAtLeast, WriteString, LimitReader, SectionReader, OffsetWriter, MultiReader, MultiWriter, TeeReader, NopCloser, Discard; no Pipe |
github.com/eugenioenko/goalchemy/std/sort |
Sort, Stable, Ints, Strings, Search, Reverse over Len/Less/Swap |
github.com/eugenioenko/goalchemy/std/unicode |
IsLetter, IsDigit, IsSpace, IsUpper, IsPrint, ToLower, ToUpper, SimpleFold, and more |
github.com/eugenioenko/goalchemy/std/unicode/utf8 |
DecodeRune, EncodeRune, AppendRune, RuneCountInString, ValidString, and more |
github.com/eugenioenko/goalchemy/std/encoding/hex |
EncodeToString, DecodeString, Encode, Decode |
github.com/eugenioenko/goalchemy/std/encoding/binary |
BigEndian/LittleEndian Uint16/32/64, PutUint*, AppendUint*, varints |
github.com/eugenioenko/goalchemy/std/encoding/json |
Marshal, MarshalIndent, Unmarshal, Encoder (NewEncoder, Encode, SetIndent, SetEscapeHTML), Decoder (NewDecoder, Decode, Token, More, UseNumber, DisallowUnknownFields, Buffered, InputOffset), Token, Delim, Marshaler, Unmarshaler, RawMessage, Number, Valid, Compact, Indent, HTMLEscape, SyntaxError, UnsupportedTypeError, UnsupportedValueError, MarshalerError (see below) |
github.com/eugenioenko/goalchemy/std/encoding/jsonvalue |
Parse/ParseWithLimits, Encode/EncodeWithLimits, Value with Kind, Get/Lookup/Has, Index, Len, Keys, typed String/Bool/Int64/Uint64/Float64 and checked As* forms, Object, Array, String, Int, Uint, Float, Number, Bool, Null, Set, Append, Limits, SyntaxError, LimitError, InvalidValueError (see below) |
github.com/eugenioenko/goalchemy/std/encoding/protojson |
Marshal, Unmarshal, UnmarshalValue, Message, Encoder, Decoder, Timestamp, Duration, Empty, FieldMask, Any, NewAny, Register, for messages generated by protoc-gen-goalchemy |
github.com/eugenioenko/goalchemy/std/http |
Do, Request, Response: an HTTP request whose body is an io.Reader and whose response body is an io.ReadCloser, streamed (cooperative gate) |
github.com/eugenioenko/goalchemy/std/connect |
Client (with SendTimeout to send Connect-Timeout-Ms, off by default), NewClient, CallUnary, HTTPClient (a caller-supplied transport with the shape of lib/http.Do), Error, ErrorDetail, Code and its constants, CodeOf: unary Connect calls with the JSON codec, used by generated service clients (cooperative gate) |
github.com/eugenioenko/goalchemy/std/time |
Time, Duration, Now, Sleep (cooperative gate), Unix, Date, Since, Until, Add/Sub/AddDate, Truncate/Round, Format/Parse for RFC3339 and RFC3339Nano, ParseDuration (UTC only; see below) |
github.com/eugenioenko/goalchemy/std/net/url |
Parse, ParseRequestURI, URL with String, Hostname, Port, Query, IsAbs, JoinPath, ResolveReference, Parse, EscapedPath, RequestURI, Redacted, Clone and MarshalBinary/UnmarshalBinary; JoinPath, PathEscape/PathUnescape, QueryEscape/QueryUnescape, Values (Get, Set, Add, Del, Has, Encode, Clone), ParseQuery, User, UserPassword, Userinfo, Error, EscapeError, InvalidHostError (see below) |
github.com/eugenioenko/goalchemy/std/net |
JoinHostPort, SplitHostPort, AddrError; no dialing, listening or name resolution |
github.com/eugenioenko/goalchemy/std/errors |
New, Is, As, Unwrap, Join, ErrUnsupported, including Unwrap() []error trees |
github.com/eugenioenko/goalchemy/std/fmt |
Sprintf, Sprint, Sprintln, Errorf with one or more %w, Append/Appendf/Appendln, Stringer, GoStringer, Formatter, State, FormatString (see below) |
github.com/eugenioenko/goalchemy/std/os |
ReadFile, WriteFile, PathError, FileMode, ErrNotExist, ErrExist, ErrPermission, ErrInvalid, MaxFileBytes (see below) |
github.com/eugenioenko/goalchemy/std/log/slog |
Logger, Default/SetDefault, New, Debug/Info/Warn/Error, their Context forms, Log/LogAttrs, With/WithGroup, Attr, Value, Level, LevelVar, Record, Handler, HandlerOptions, LogValuer, DiscardHandler and NewHostHandler (see below) |
github.com/eugenioenko/goalchemy/lib/errors |
New, Is, Unwrap; the native layer under std/errors, whose Is does not follow Unwrap() []error |
github.com/eugenioenko/goalchemy/lib/sync |
Mutex, WaitGroup (cooperative gate) |
github.com/eugenioenko/goalchemy/lib/context |
Context, CancelFunc, Background, WithCancel, WithTimeout, Canceled, DeadlineExceeded, and the Done and Err methods (cooperative gate) |
github.com/eugenioenko/goalchemy/lib/time |
Duration, its unit constants, and Sleep (cooperative gate); a separate type from std/time.Duration |
github.com/eugenioenko/goalchemy/lib/runtime |
Gosched (cooperative gate) |
github.com/eugenioenko/goalchemy/lib/task |
All (cooperative gate) |
github.com/eugenioenko/goalchemy/lib/crypto |
Key, SHA-256, HMAC-SHA256, HKDF-SHA256, AES-256-GCM, RSA OAEP (2048, 3072 and 4096-bit), RS256/384/512, ES256/384/512, P-256/P-384/P-521 ECDH, key generation, PEM and JWK |
github.com/eugenioenko/goalchemy/lib/encoding |
Base64Encode, Base64Decode, Base64URLEncode, Base64URLDecode |
github.com/eugenioenko/goalchemy/lib/http |
Do, a bounded GET or POST exchange, DoWith, the same with transport options, and Open, an Exchange whose bodies are written and read in chunks |
github.com/eugenioenko/goalchemy/lib/clock |
Unix and UnixNano, host wall-clock seconds and nanoseconds |
github.com/eugenioenko/goalchemy/lib/log |
Enabled and Emit, the host log sink behind std/log/slog |
github.com/eugenioenko/goalchemy/lib/os |
ReadFile and WriteFile with portable status codes, the host file system behind std/os |
github.com/eugenioenko/goalchemy/lib/callback |
Request, a bounded call to a host-registered callback |
The runtime library reference documents every function. For lib/ it lists the gate, bounds, error behavior, per-target availability and native dependencies. It is generated from the std/ and lib/ sources and the contracts with make spec-generate.
std/time differs from Go’s time in these ways:
- Every
Timeis UTC.UTCis the onlyLocation;Parseapplies a numeric offset and returns the UTC instant, so the original offset is not kept. FormatandAppendFormataccept onlyRFC3339andRFC3339Nanoand panic on any other layout.Parsereturns an error for any other layout. For these two layouts,Parseaccepts and rejects the same inputs as Go, with the same error text.Nowhas no monotonic reading, soSince,UntilandSubfollow host clock adjustments.Nowprecision is the host clock’s: milliseconds on TypeScript, microseconds or better elsewhere.Sleeptakes astd/time.Durationand delegates tolib/time.Sleep.lib/time.Duration, used bylib/context.WithTimeout, is a separate type; convert withlibtime.Duration(d).
std/net/url is a port of the reference toolchain’s net/url, with the same parsing rules, escaping, results and error text, checked against it by Go unit tests:
- Parsing follows the defaults Go applies to a module declaring
go 1.25, the Goalchemy source baseline: a host with several colons, such ashttps://example.com:80:, is accepted (GODEBUGurlstrictcolons=0), andParseQueryrejects more than 10000 parameters. - Bracketed IPv6 hosts are validated as
net/netip.ParseAddrdoes, with its error text, without depending onnet/netip. Error.Errvalues carry Go’s messages. Errors Go builds withfmt.Errorfareerrors.Newvalues here, and theinvalid host:error still unwraps to its cause.
std/fmt and std/errors work without reflection:
fmtformats operands that are nil, booleans, integers, floats and strings of predeclared types,[]byte, and values whose type implementsFormatter,GoStringer(for%#v),errororStringer. Verbs, flags, width, precision, argument indexes, and the%!verb(...),MISSING,BADINDEXandEXTRAnotes match Go for these operands. The compiler rejects other operand types, such as structs, maps, pointers without methods and named basic types without methods, when their static type is known (GCS006); behind an interface they print as%!v(unsupported). Convert named basic types, as inint(level), or give them aStringmethod.%Tand the type names in bad-verb andEXTRAnotes are known only for the basic types above and print as?otherwise.%pprints%!p(unsupported).- A method that panics prints
%!v(PANIC=String method: ...)as in Go, except that any nil pointer dereference prints<nil>, where Go does so only for a nil receiver. Sprinttreats only predeclaredstringoperands as strings when deciding where to add spaces; Go also treats named string types as strings.errors.Asneeds a target whose static type is a pointer to an interface type or to a type implementingerror. The compiler expands each call for that type and rejects other targets,errors.Asused as a function value, anddeferorgoof it (GCS006). A nil target pointer panics as in Go.fmt.Print,PrintfandPrintlnare not available; use theprintandprintlnbuiltins withfmt.Sprintf.
std/log/slog follows Go’s log/slog API, and the host application decides where records go:
- The default logger, and any logger built with
slog.NewHostHandler, sends records to the host log sink. A record goes out when it passes the handler’sHandlerOptions.Level, if set, and the host’s minimum level. Until the host installs a sink, that minimum isLevelWarnand records are written to standard error, so libraries are quiet by default. - Records are rendered like
slog.TextHandlerwithout thetimeattribute, for examplelevel=WARN msg=retry kas=https://kas attempt=2. The sink also receives the level, message, Unix time in nanoseconds and the attributes as key/value strings, with group names joined to keys by.. - Values are rendered through
std/fmt, so thefmtoperand rules above apply. The compiler rejects attribute values of unsupported static types, unless they implementLogValuerorMarshalText(GCS006). - Source locations are not recorded:
HandlerOptions.AddSourceis ignored,Record.PCis anintthat is always zero, andNewRecordtakes anintfor its unusedpcargument.ReplaceAttris not called fortime, which the host handler does not render. - There is no
TextHandlerorJSONHandler, because there is noio.Writer; implementHandlerfor custom output. Handlers take alib/context.Context, which the default methods fill withcontext.Background().
Hosts install a sink before calling into a library. The handler runs synchronously on the calling thread and must not block or call back into the library; exceptions and panics it raises are discarded. Levels follow log/slog: -4 debug, 0 info, 4 warn, 8 error.
| Target | Install a sink | Record |
|---|---|---|
| Go | log.SetHandler(func(log.Record), level) from goalchemyout/cap/log; log.Slog(*slog.Logger) adapts a Go logger |
Level, Time, Message, Attrs (key/value pairs), Text |
| TypeScript | setLogHandler(record => ..., level) exported by the library |
level, unixNano, time, message, attrs ([key, value] pairs), text |
| Python | set_log_handler(handler, level) exported by the library; logging_handler(logger) forwards to the logging logger goalchemy |
LogRecord with level, unix_nano, time, message, attrs, text |
| Java | io.goalchemy.runtime.Log.setHandler(record -> ..., level); Log.systemLogger() forwards to System.Logger goalchemy |
Log.Record with level(), unixNano(), time(), message(), attrs(), text() |
| C# | Rt.Log.SetHandler(record => ..., level); Log.TraceHandler() writes to System.Diagnostics.Trace |
Log.Record with Level, UnixNano, Time, Message, Attrs, Text |
| Rust | set_log_handler(Some(Arc::new(|r: &LogRecord| ...)), level) exported by the crate |
LogRecord with level, unix_nano, time(), message, attrs, text |
| C | gxc_set_log_handler(handler, state, level) in goalchemy.h |
gxc_log_record with lengths and NUL-terminated copies, freed when the handler returns |
| Swift | setLogHandler({ record in ... }, level:) exported by the module |
GoalchemyLogRecord with level, unixNano, time, message, attrs, text |
Passing a null handler (nil, None, NULL) restores the default standard error sink at LevelWarn. Strings reach the handler decoded as UTF-8, with invalid sequences replaced; C receives the raw bytes.
std/encoding/json encodes and decodes Go values exactly as the reference toolchain’s encoding/json does, without reflection:
- The compiler describes the static type of each
MarshalandMarshalIndentoperand, and the type anUnmarshaltarget points to, with every type reachable from it, following Go’s rules for struct tags, embedded fields,omitempty, thestringoption, map key ordering,[]byteas base64, nil slices and maps asnull, pointer cycles,Marshalerandencoding.TextMarshaler(including pointer-receiver methods on addressable values), HTML escaping and float formatting. - Types encoding/json cannot encode, such as channels, functions, complex numbers and maps with other key types, are rejected at compile time (
GCS006) unless the field is excluded withjson:"-". - Struct tags are limited to names made of letters, digits and the punctuation encoding/json has always accepted, and to the
omitemptyandstringoptions. Other names and options,omitzero, thestringoption onjson.Number, andjsontags on unexported fields are rejected (GCS006), because their meaning differs between Go releases. - Values held in interfaces, such as
anyfields,[]anyandmap[string]any, are encoded from their dynamic value when it is nil, a boolean, integer, float or string of a predeclared type,[]byte,[]any,map[string]any, or implementsMarshalerorencoding.TextMarshaler, asjson.Number,json.RawMessageandjsonvalue.Valuedo. Other dynamic values, such as structs and named types without these methods, are rejected when the compiler sees them stored in an interface in theMarshaloperand, and return*UnsupportedTypeErrorotherwise; Go encodes them by reflection. UnsupportedTypeError.TypeandMarshalerError.Typeare type names (string) rather thanreflect.Typevalues, andUnsupportedValueErrorhas noValuefield. TheirErrortext matches Go.json.NumberimplementsMarshalJSONandUnmarshalJSON, so an invalid number literal is reported as a*MarshalerErrorwhen encoding, and decoding errors carry no offset or field, as Go’sNumberreports them.Unmarshalfollows Go for case-insensitive field names (strings.EqualFold), ignored unknown members, duplicate members (the last one wins),null(which sets pointers, slices, maps and interfaces to nil and leaves other values unchanged), merging into existing structs, slice elements, arrays and pointed-to values, thestringoption,Unmarshalerandencoding.TextUnmarshaler(includingnullpassed toUnmarshalJSON), base64[]byte, decoding intoanyasmap[string]any,[]any,float64,string,boolornil, invalid UTF-8 replaced by U+FFFD, and continuing after a type error to return the first one.SyntaxErrorandUnmarshalTypeErrorcarry Go’s messages, offsets,StructandFieldvalues.Unmarshalneeds a target whose static type is a pointer or an interface. Other targets, types it cannot decode such as channels, functions, complex numbers and map keys that are not strings, integers orencoding.TextUnmarshaler, and embedded pointers to unexported struct types are rejected (GCS006).- An interface target, or an interface field that already holds a non-nil pointer, is decoded into when that pointer is a
*any,*map[string]any,*[]any,*string,*boolor*float64, or implementsUnmarshalerorencoding.TextUnmarshaler. Other pointers are rejected when the compiler sees the conversion and return*UnsupportedTypeErrorotherwise; Go decodes into them by reflection. Interface fields that hold nothing or a non-pointer are replaced by the decodedanyvalue, as in Go. UnmarshalTypeError.TypeandInvalidUnmarshalError.Typeare type names (string). TheErrof anUnmarshalTypeErrorfor invalid base64 or a non-stringencoding.TextUnmarshalerinput has Go’s text but is not abase64.CorruptInputError.Encoder.EncodeandDecoder.Decodecheck and encode or decode their operand likeMarshalandUnmarshal.Encoderfollows Go for the trailing newline,SetIndent,SetEscapeHTMLand a write error that stops later calls.Decoderreads from anystd/ioreader, such as a streamed HTTP body, and reproduces the reference toolchain’s decoder (Go 1.27, built onencoding/json/v2) forToken,More,InputOffset,Buffered, buffering, syntax errors and their offsets,io.EOFandio.ErrUnexpectedEOF,UseNumberandDisallowUnknownFields.Marshal,MarshalIndent,Unmarshal,Encoder.EncodeandDecoder.Decodecannot be used as function or method values or withdeferorgo(GCS006). AnEncoderorDecodercalled through an interface of your own encodes and decodes like ananyoperand.
std/encoding/jsonvalue handles JSON whose shape is not fixed, such as JWT claims or partly read responses, as a tree of values. It differs from Go’s encoding/json in these ways:
- Build and inspect
Valuetrees instead of Go types. AValueimplementsjson.Marshalerandjson.Unmarshaler, so it can be passed to, or be a field of a value passed to,json.Marshalandjson.Unmarshal; decoding parses withParse, so the rules below apply. - Numbers keep their source text.
Numberreturns it,Int64/Uint64accept only integer text that fits (1.0and1e3are rejected), andFloat64rounds to the nearest float64. - Duplicate object member names are a syntax error when parsing and an
InvalidValueErrorwhen encoding; Go keeps the last one. - Parsing and encoding are bounded by
Limits: by default 16 MiB of input or output, nesting depth 128 (MaxDepth), 1Mi values and 16 MiB per string. - Accessors never panic. A missing member, an out-of-range index or a value of another kind returns the zero result, and
Existsreports a failed lookup. Stringreturns the content of a JSON string and the compact encoding of any other value, sofmtprints values as JSON. UseAsStringto require a string.- Strings are encoded as
json.Marshalencodes them, including\u003c,\u003eand\u0026for<,>and&. Invalid UTF-8 and unpaired surrogate escapes become U+FFFD, as in Go.
std/os reads and writes whole files:
- Errors are
*PathErrorvalues with Go’sOp,Pathand Linux error text, for exampleopen key.pem: no such file or directory.errors.IsmatchesErrNotExist,ErrExist,ErrPermissionanderrors.ErrUnsupportedas in Go, anderrors.Asfinds the*PathError. Reading a directory fails with opread, as on Linux; other failures use opopen. - Failures are reported in these classes: not found, exists, permission denied, is a directory, not a directory, file too large, operation not supported, invalid argument (for a NUL byte in the name), and input/output error for anything else.
- Files and data larger than
MaxFileBytes(1 GiB) are rejected withfile too large. WriteFilecreates a missing file withpermminus the process umask and keeps the permissions of an existing file it truncates, as in Go. Only the low nine permission bits are applied; hosts without POSIX permissions ignore them.- Names are byte strings passed to the host unchanged on Go, TypeScript (Node), Python, Rust, C and Swift. Java and C# decode them as UTF-8, replacing invalid sequences. Relative names resolve against the process working directory.
- Calls are synchronous and never suspend the cooperative scheduler. TypeScript reads files only through the Node entry points (executables and the library package’s
nodeexport, which install thenode:fsadapter); in browsers and other portable hosts every call fails withoperation not supported.
Every package is ordinary Go, so programs still build and run with the Go toolchain. Importing a standard package such as "sync", "strings" or "fmt" directly is rejected with a remedy naming its std/ or lib/ replacement.
Cooperative execution
Section titled “Cooperative execution”With -gate cooperative (or gate: cooperative in goalchemy.yaml), programs may use go, channels, select, and the synchronization capabilities above. Only one task runs at a time:
- Runnable tasks run in FIFO order. A task keeps control until it blocks, yields, returns, or panics.
selectchooses among ready cases with a seeded xorshift32 source:GOALCHEMY_SEED, default 1.- The default entry uses a virtual clock for
time.Sleepand context deadlines, advancing only when every task is blocked. Generated programs that uselib/crypto,lib/httporlib/callbackstart on their target’s host entry instead, with owner-local monotonic real time. TypeScript cooperative output can select real time through portablehost.ts/runHost; its module-global source state is not an isolated library instance. Java cooperative output exposesMain.runHost()with the same executable-global limitation andSystem.nanoTimedeadlines. C# cooperative output exposes Task-returningGoProgram.runHost()withStopwatchdeadlines and serialized executable globals; it is not an isolated library API. Python cooperative output exposes blockingmain.runHost()withmonotonic_nsdeadlines, native mailbox completion and serialized executable globals; it is not an SDK library. C cooperative output exposesgoalchemy_run_host()with checked monotonic deadlines, owned native wire records and resource ACK before return; see the C executable boundary and limits. - A deadlock prints
fatal error: all goroutines are asleep - deadlock!and exits with status 2.
Every target follows the same scheduler contract and the same shared lowering:
- Effect analysis finds the functions that may suspend: those that use channels,
select, or suspending capabilities, directly or through calls, function values, or interface methods. - The shared IR pass cuts each of those functions at its pause points into continuation blocks. The function becomes a resumable frame: an object holding its locals and the block to resume at.
- Each runtime provides pause primitives (
recv,send,select, lock, sleep, spawn) and a trampoline scheduler. Deferred calls,panic, andrecoverin frames are managed by the runtime, per task.
No target relies on native coroutines or threads for source tasks.
Generated Go lib/http.Do runs the bounded native transport on host workers.
Workers enqueue owned completions; the scheduler alone resumes source tasks,
so concurrent source cancellation remains runnable during network and body
reads. Context deadlines start at creation and an earlier parent deadline
shortens the required real HTTP timeout. Entry return cancels and cleans pending
background operations. Other targets run lib/http.Do through their own host
adapters; exported asynchronous libraries remain gated. See
host lifecycle and target-port requirements.
github.com/eugenioenko/goalchemy/lib/task provides task.All(fns ...func()). It runs each function as a task, in argument order and one at a time, and returns when all have finished. With the Go toolchain the same package runs the functions as goroutines.
HTTP transport options
Section titled “HTTP transport options”http.DoWith takes the arguments of http.Do plus options as alternating
names and values:
| Option | Value |
|---|---|
http.ClientCert and http.ClientKey |
PEM client certificate (chain) and unencrypted private key (PKCS#8, PKCS#1 or SEC1), offered when the server asks for one (mTLS). Both or neither. |
http.RootCAs |
PEM certificates trusted in addition to the system roots |
http.InsecureSkipVerify |
"true" disables server certificate and host name verification; "false" is the default |
http.UnixSocket |
Path of a Unix domain socket to connect to instead of the URL’s host (no proxy). The URL host still sets the Host header and, for https, the server name that is verified. |
Server certificates are verified unless InsecureSkipVerify is "true".
Odd, unknown or repeated options fail as invalid requests; certificates or
keys that do not parse fail with http: invalid TLS option.
Windows named pipes and plaintext HTTP/2 (h2c) are not available.
| Target | TLS options | UnixSocket |
|---|---|---|
| Go | crypto/tls in net/http |
net.Dialer on unix |
| TypeScript (Node) | node:https cert, key and ca (with tls.rootCertificates) |
socketPath |
| TypeScript (browser) | Not supported: any option fails with http: transport options are not supported in browsers |
Not supported |
| Python | ssl.SSLContext (load_cert_chain reads the credentials from a private temporary directory) |
AF_UNIX socket under http.client (POSIX) |
| Java | SSLContext from in-memory key and trust stores in java.net.http.HttpClient |
Not supported: HttpClient connects only over TCP, so the option fails with http: unix sockets are not supported on this host |
| C# | SocketsHttpHandler.SslOptions with a custom-root chain check |
ConnectCallback with UnixDomainSocketEndPoint |
| Rust | reqwest with rustls: Identity, merged root certificates |
ClientBuilder::unix_socket (Unix hosts) |
| C and Swift | libcurl certificate blobs, roots added to the OpenSSL store | CURLOPT_UNIX_SOCKET_PATH |
Streamed HTTP bodies
Section titled “Streamed HTTP bodies”std/http.Do sends a Request whose Body is an io.Reader and returns a
Response whose Body is an io.ReadCloser, so bodies larger than
lib/http.MaxBytes pass through without being held in memory:
resp, err := http.Do(ctx, &http.Request{ Method: "POST", URL: url, Body: file, ContentLength: size, TimeoutMillis: 600000, Options: []string{lhttp.RootCAs, ca},})if err != nil { return err}defer resp.Body.Close()_, err = io.Copy(out, resp.Body)- A
BodywithContentLengthzero or less is sent chunked. TimeoutMillis(up to 24 hours) bounds the whole exchange, including reading the response body, like Go’sClient.Timeout. Cancelingctxalso ends it.- Redirects are not followed, and compression is neither requested nor decoded.
Optionsare the transport options.- It runs on
lib/http.Open: anExchangewithWrite,Response,ReadandClose, each moving at most 1 MiB.
| Target | Exchange |
|---|---|
| Go | net/http with an io.Pipe request body |
| TypeScript (Node) | node:http/node:https, writes waiting for each flush and the response read in paused mode |
| TypeScript (browser) | fetch, with the limits below |
| Python | http.client with chunked framing |
| Java | java.net.http.HttpClient with an InputStream body publisher fed one chunk at a time |
| C# | HttpClient with a custom HttpContent fed one chunk at a time |
| Rust | reqwest with a channel-fed http_body::Body on a per-exchange Tokio thread |
| C and Swift | a libcurl transfer thread per exchange, pausing its read and write callbacks |
Browsers cannot stream request bodies over HTTP/1.1, so in a browser the
request body is collected (at most 64 MiB) and sent when the response is
requested; the response body still streams. Browser fetch decodes
compressed responses itself.
lib/task: optional futures
Section titled “lib/task: optional futures”Ordinary calls infer whether they can pause; they need no task.Await.
Use futures when work should start now and its results are needed later:
import "github.com/eugenioenko/goalchemy/lib/task"
a := task.Start(func() ([]Task, error) { return fetchTasks(u1) })b := task.Start(func() ([]Task, error) { return fetchTasks(u2) })ta, errA := task.Await(a)tb, errB := task.Await(b)Start accepts a function with no parameters and any number of results,
including named functions and bound methods. It queues the task and returns
without yielding. Await returns the function’s original result list. A
completed future returns immediately; a pending future parks its awaiter.
Waiters resume through Goalchemy’s FIFO scheduler under both pause models.
Awaiting again returns the same results. Struct and array results copy by value; pointers, slices, and maps retain their usual Go sharing rules. A started task’s panic is raised independently in every awaiter, so each awaiter can recover it. An unobserved panic is fatal when the program entry finishes or before the scheduler reports a deadlock. Cancellation follows the contexts captured by the started function.
Futures can be stored in containers and sent through channels. When an explicit type is needed, write the zero-argument function signature:
var pending []task.Future[func() ([]Task, error)]pending = append(pending, task.Start(func() ([]Task, error) { return fetchTasks(u1)}))tasks, err := task.Await(pending[0])Future is a compiler-known typed carrier; this notation does not enable
user-defined generic functions or types. A zero future never completes and
participates in normal deadlock detection. Futures cannot cross an exported
library API or be retained inside an exported handle: await inside the
library and export the completed results. task.All and ordinary go
statements can be mixed with futures.
Goalchemy source uses task.Await(f). The reference Go runner normalizes this
to the callable result bridge task.Await(f)() before running the gc toolchain.
Generated Go uses typed runtime calls and builds with the ordinary Go compiler.
Behavior Go leaves open
Section titled “Behavior Go leaves open”Goalchemy fixes some behavior that Go leaves to the implementation. These choices are identical on every target:
- Map iteration follows insertion order. An entry deleted before it is visited is skipped, and entries inserted during iteration are not visited.
- When
appendexceeds capacity, the new capacity ismax(needed, max(1, 2*cap)). []byte(s)and[]rune(s)have capacity equal to their length.- Operands are evaluated left to right wherever Go allows a choice.
Byte storage
Section titled “Byte storage”TypeScript byte slices and arrays use Uint8Array, including named types
with underlying uint8 elements. Slice views share native storage; byte
string conversions copy and preserve arbitrary Go string bytes. Java byte
slices and arrays use native byte[], with unsigned reads through
Go’s existing long integer representation. Java preserves aliases, zeroed
capacity and arbitrary-byte string copies too. C# byte slices and arrays use
native byte[], with primitive reads widened to Go long, zeroed capacity,
shared views and independent arbitrary-byte string copies. Python byte slices
and arrays use native bytearray, with fixed-length shared views, zeroed
capacity and independent conversions to/from immutable bytes Go strings.
Rust byte slices and arrays use traced native Vec<u8> backing, with typed nil
headers, zeroed capacity, shared views and independent binary string copies.
C byte slices and arrays use collector-owned native uint8_t backing, with
typed nil headers, zeroed capacity, shared interior views and independent
binary string copies. See the bounded TypeScript evidence,
Java evidence, C# evidence
Python evidence, Rust evidence
and C evidence
for coverage and remaining SDK, browser and library requirements.