ABI generator architecture
Documentation status: architecture — see Maturity and evidence.
Role
The generator transforms the explicitly published Runtime surface into a verifiable interoperability contract and then into idiomatic bindings for supported ecosystems.
It does not copy engine-internal classes and does not publish their memory layout. Its responsibility is to produce a stable public projection.
flowchart LR
PUB[Published Runtime surface] --> MODEL[Canonical publication model]
MODEL --> MANIFEST[ABI manifest]
MODEL --> NATIVE[Local ABI exports]
MODEL --> DOTNET[.NET binding]
MODEL --> FUTURE[Future bindings]
MANIFEST --> TESTS[Contract tests]
Current certification boundary
The generator model is intentionally broader than the generic executor currently certified in the engine. In the current source, the manifest vocabulary already describes strings, arrays, records, callbacks, bytes, wider integers, and floating-point values, while the generic native argument/execution path is presently tested end to end for i32, pointer, handle, and void results.
Therefore, sections below that discuss arrays, callbacks, async/cancellation metadata, or richer scalar projections describe the target publication/generation architecture, not a claim that every value kind is already executable through the current generic ABI marshaller. See Marshalling and value kinds for the certified subset.
Recommended pipeline
1. Discover the published surface
The generator considers only types and members explicitly intended for interoperability. An internal class never becomes public merely because reflection can see it.
Each published member must provide enough information to determine:
- public name;
- stable identifier;
- parameters;
- return value;
- nullability;
- ownership;
- async/cancellation capabilities;
- nested types or collection element types.
2. Build a canonical model
Before emitting C#, Rust, or a native export, the generator builds a language-neutral model.
This prevents implementation-language conventions from leaking into public SDKs and allows the same contract to be projected into multiple ecosystems.
3. Close the public type graph
Every type reachable from a published signature must itself have a valid public projection.
A correct generation has only two outcomes:
- the complete signature is projected;
- generation fails with a precise diagnostic.
Using an opaque pointer as an accidental fallback for an unknown type is not acceptable for a public API.
4. Generate the manifest
The manifest is the machine-readable publication contract and must be useful independently of generated C# source.
Conceptual example:
{
"bindingVersion": "2",
"abiVersion": "3",
"capabilities": ["object-arrays", "callbacks"],
"types": [
{
"typeId": 1201,
"publicName": "Worker",
"members": []
}
]
}
These values are illustrative; effective identifiers come from the generated manifest for a specific release.
5. Generate local exports
The local layer translates the canonical contract into operations used by the native runtime client while preserving:
- runtime identity and affinity;
- type descriptors;
- ownership;
- structured errors;
- callbacks;
- supported arrays and collections.
Packing details remain internal to the binding.
6. Project into each ecosystem
Each backend applies language conventions without changing contract meaning.
For .NET:
- PascalCase public types and members;
- camelCase parameters and locals;
IDisposablefor owning wrappers;CancellationTokenonly when cancellation is meaningful;Asynconly for genuinely asynchronous operations.
Future bindings should follow the same principle: idiomatic source APIs with identical semantics.
Collections
The target contract should handle one-dimensional arrays of primitive values, strings, and published objects uniformly.
An object collection is not merely an array of handles: each element retains Runtime identity, affinity, and ownership. The projection must construct the correct public wrapper for each returned object.
Callbacks
The generator should emit typed callback signatures and document their lifetime.
The binding retains delegates or callbacks for as long as the Runtime may invoke them. Application code should not manually create function pointers when a public wrapper exists.
Async and cancellation contracts
The manifest should explicitly describe whether an operation is:
- synchronous;
- asynchronous;
- client-wait cancelable;
- transport cancelable;
- cooperatively cancelable by the Runtime;
- a durable cancelable job.
This prevents semantics from being inferred from naming or topology.
Generated tests
Binding generation should be accompanied by contract tests covering at least:
- scalars;
- strings;
- nullability;
- enums;
- arrays;
- objects;
- ownership;
- callbacks;
- errors;
- local/RPC parity where available.
Documentation should also be able to validate every referenced public symbol against the manifest for the release being documented.
Documentation rule
Examples on this site use public binding names only. Private identifiers and engine implementation-language conventions are not part of the developer vocabulary.
See also: