This document describes the runtime data shapes that Ion-generated C and the standard library agree on. It is intentionally a beta-facing contract, not a promise that every internal helper symbol is stable before 1.0.
- Generated C is the compiler/runtime ABI boundary.
- Ion values are owned by exactly one binding unless borrowed through
&Tor&mut T. - Owned values with runtime resources are dropped exactly once by generated scope-exit code.
- References are stack-only views and must not be stored in runtime containers or sent across threads.
String is an owned runtime allocation for byte strings. Its C layout uses a
uint8_t* data pointer plus length and capacity fields. String iteration in the
beta subset is byte iteration (u8), not Unicode scalar-value or grapheme
iteration.
Stable beta expectations:
String::new,String::from,String::len,String::push_str, andString::push_bytepreserve ownership of theStringreceiver unless a function explicitly consumes it.String::push_strappends string literals or ownedStringvalues (the latter reads.data/.lenfrom the source heap buffer).- Dropping a
Stringreleases its backing allocation once. String == StringandString != Stringcompare byte contents.
Vec<T> is an owned dynamic array with pointer, length, and capacity. The C
backend monomorphizes element-specific helpers where needed.
Stable beta expectations:
Vec::new,Vec::push,Vec::pop,Vec::get,Vec::get_ref,Vec::set,Vec::len, andVec::capacityremain available through the stdlib/builtin surface.- Dropping
Vec<T>drops owned elements whenTneeds destruction. - Bounds-sensitive operations either return
Option<T>where documented or trigger the runtime panic path for checked indexing. Vec::get/Vec::popreturn heapOptionblobs from the runtime; generated C unpacks them withion_option_from_rawinto monomorphizedOption_Tstack values (tag plus payload atdata.variant_0.arg0).matchonVec::get/Vec::popresolvesOption<T>from the call's return type or the vector argument's element type (not the firstVecin the program).Vec::get_refreturns a stack-localOption<&T>: codegen fills tag and a pointer into the vector buffer (orNonewhen out of bounds). No runtime heapOptionand noion_option_from_raw. Monomorphized names use theref_prefix (for exampleOption_ref_int,Option_ref_Product). Match arms onOption::Some(x)bind drop-owningTasT*; copy types bind by value from*arg0. Scope cleanup must not drop nested owned fields through the binding.- Monomorphized container typedefs use Ion type names (
Vec_String,Option_Customer), not C runtime typedefs (ion_string_t, etc.). &mut Vec<T>parameters codegen asVec_T**; builtins dereference once when passing the receiver toion_vec_push,ion_vec_get, and related helpers.Vec::get_refuses the sameion_vec_t*receiver but does not callion_vec_get; it bounds-checks and takes the address of the slot in generated C.
Box<T> owns one heap-allocated T.
Stable beta expectations:
Box::newallocates and owns a value.Box::unwrapconsumes the box and returns the owned payload.- Dropping a
Box<T>drops the payload and releases the allocation once.
Fixed arrays [T; N] are inline values. Slices []T are fat views carrying a
data pointer and length. Safe indexing emits runtime bounds checks; indexing
inside unsafe blocks may omit those checks.
Struct layout is C-oriented and field-order preserving in generated C. Enum
layout is compiler-generated and should be treated as stable only for C emitted
by the same Ion compiler/runtime version unless a beta release explicitly
documents a layout guarantee. Enum literals (Enum::Variant(...)) lower to C
compound initializers ((Enum_T){ .tag = N, .data = { ... } }); the compiler
does not emit per-variant _new helper functions.
Channels are typed ownership-transfer queues backed by the C runtime. Sending a
value moves ownership into the channel; receiving moves ownership out. spawn
creates an OS thread and transfers only structurally Send values into the
thread context.
Stable beta expectations:
- References do not cross channel or thread boundaries.
- Channel handles are runtime resources and are released by generated drops.
- Runtime failures such as allocation or thread creation failures call the Ion panic path.
Generated code is responsible for normal-scope destruction. Runtime panics abort the process; they are not currently exception-style unwinds. Code that relies on drop execution after a runtime panic is outside the beta contract.