Techniques¶
The implementation is an arena plus a few parsers. Nothing in the hot path calls out to another Ion library.
One arena, many lists¶
An IonDoc owns nodes, edges, strings, symbol records, limbs, float bits,
timestamps, and blob bytes. A node is four integers plus annotation and child
indexes. Containers do not embed children. add_child appends an edge and
links it from the parent's tail, which keeps field order without a second walk
to find the end.
Sharing a scalar node is safe. Macro expansion does that: each use of a template copies the container spine and points at the same integer or string node. Annotations that the template adds are copied onto a fresh node so the template itself does not change.
Depth is capped at 1024. A deeper list, s-expression, or struct raises
DecodeError.KIND_DEPTH.
Symbol segments¶
A local table is a list of segments. The first segment is the nine system
symbols. A local declaration appends a segment whose text lives in the table.
An import appends a segment that records the shared table's real symbols and
a count for the unknown tail. The table does not allocate a string per unused
id, so a max_id in the hundreds of millions stays small.
Catalog.exact demands one name and one version. Catalog.greatest returns
the highest version of that name. Ion 1.0 import rules use greatest when
max_id is present and exact when it is not.
Equivalence¶
ion_eq compares two nodes.
| Type | Rule |
|---|---|
| Annotations | Same texts, in order. |
| Struct | Same fields as a multiset. Order does not matter. |
| List and s-expression | Same values, in order. |
| Int | Same sign and the same limbs. |
| Decimal | Same sign, coefficient, and exponent. 1.0 is not 1.00. |
| Float | Numeric value. All NaNs are equal. -0 equals only -0. |
| Timestamp | Precision, offset, and every stored field. |
| Symbol | Known text, or the same unknown import. A local unknown equals symbol zero. |
Ion 1.1 macros¶
A directive (:$ion set_macros (point {x: (:?), y: (:? 0)})) stores the struct
as a template. (:?) is a hole with no default. (:? 0) is a hole whose
default is the integer zero. (:point 5 (:)) supplies 5 and an absent
second argument, so the expansion is {x: 5, y: 0}.
The binary form uses opcodes 0xE3 and 0xE4 for the directive, 0xE9 and
0xEA for placeholders, and 0x00 through 0x47 for a macro address. Opcode
0xE0 inside an argument list is the absent argument. At the top level the
same byte begins a version marker.
What the writer guarantees¶
Two encodes of one value with the same EncodeOptions produce the same bytes.
Binary output may differ from a particular input when that input used NOP
padding or different symbol ids. Ion 1.1 output prefers inline symbol text, so
it does not need a local symbol table. Ion 1.0 binary output emits one when
any non-system symbol appears.