iceberg · API

iceberg.json

A small, dependency-free JSON reader/writer for Iceberg metadata.

Why not EmberJson? It resolves fine on both pixi environments (emberjson 0.3.4 from modular-community), but the package ships a precompiled emberjson.mojoc built with Mojo 1.0.0, and the nightly compiler hard-errors on it:

error: Mojo precompiled file is incompatible with the current version of the
Mojo compiler. Precompiled file '.../emberjson.mojoc' version 1.0.0 is older
than compiler version 1.1.0.dev2026082905.

Since this tin must build on both default (nightly) and stable, the parser lives here instead. It is deliberately small: Iceberg metadata JSON is at most a few hundred KB.

Design: an arena DOM. Every value is a JsonNode in Json.nodes, and containers refer to their children by index. Recursive Mojo data types are awkward; integer indices are not.

Numbers are the one place correctness really bites. Snapshot ids, sequence numbers and last-updated-ms are signed 64-bit and must survive a parse → serialize round trip exactly, so integers are accumulated into Int64 digit by digit and are never routed through Float64. A number is only treated as a floating-point value when it actually carries a ., an e or an E.

Structs

JsonNode

struct JsonNode

One JSON value. Containers hold child node indices, not child values.

Implements Copyable, Movable

Fields
kind: UInt8
b: Bool
i: Int64
f: Float64
s: String
keys: List[String]: Object member names, parallel to children. Empty for arrays.
children: List[Int]: Indices into Json.nodes of the array elements / object values.

null

def null() -> Self

bool_

def bool_(v: Bool) -> Self

int_

def int_(v: Int64) -> Self

float_

def float_(v: Float64) -> Self

string_

def string_(var v: String) -> Self

array_

def array_(var kids: List[Int]) -> Self

object_

def object_(var keys: List[String], var kids: List[Int]) -> Self

Json

struct Json

A parsed JSON document: an arena of nodes plus the index of the root.

Implements Copyable, Movable

Fields
nodes: List[JsonNode]
root: Int

__init__

def __init__(out self)

add

def add(mut self, var node: JsonNode) -> Int

kind

def kind(self, i: Int) -> UInt8

is_null

def is_null(self, i: Int) -> Bool

size

def size(self, i: Int) -> Int

Number of elements (array) or members (object).

at

def at(self, i: Int, k: Int) -> Int

Index of array element / object value k.

key_at

def key_at(self, i: Int, k: Int) -> String

get

def get(self, i: Int, key: String) -> Int

Index of object member key, or -1 when absent.

has

def has(self, i: Int, key: String) -> Bool

as_int

def as_int(self, i: Int) -> Int64

as_float

def as_float(self, i: Int) -> Float64

as_string

def as_string(self, i: Int) -> String

as_bool

def as_bool(self, i: Int) -> Bool

opt_int

def opt_int(self, i: Int, key: String, dflt: Int64) -> Int64

req_int

def req_int(self, i: Int, key: String) -> Int64

opt_string

def opt_string(self, i: Int, key: String, dflt: String) -> String

req_string

def req_string(self, i: Int, key: String) -> String

opt_bool

def opt_bool(self, i: Int, key: String, dflt: Bool) -> Bool

string_map

def string_map(self, i: Int, key: String) -> Dict[String, String]

Read an object of string→string (Iceberg properties and friends).

int_list

def int_list(self, i: Int, key: String) -> List[Int]

string_list

def string_list(self, i: Int, key: String) -> List[String]

dump

def dump(self, i: Int) -> String

Compact JSON text for the subtree rooted at i.

dump_root

def dump_root(self) -> String

Functions

write_json_string

def write_json_string(s: String, mut out: String)

Append s as a quoted, escaped JSON string.

json_quote

def json_quote(s: String) -> String

format_double

def format_double(v: Float64) -> String

Render a double the way Iceberg's JSON writers do.

-0.0 keeps its sign (it is a distinct bound value), and non-finite values become the strings Jackson emits, since JSON has no literal for them.

parse_int64

def parse_int64(s: String) -> Int64

Exact decimal → Int64, including -9223372036854775808.

encode_utf8

def encode_utf8(cp: Int, mut out: List[UInt8])

parse_json

def parse_json(text: String) -> Json

Parse a complete JSON document.

substr

def substr(s: String, start: Int, end: Int) -> String

Byte-range substring. Mojo's String has no slice syntax.

Aliases

comptime JSON_NULL = UInt8(0)
comptime JSON_BOOL = UInt8(1)
comptime JSON_INT = UInt8(2)
comptime JSON_FLOAT = UInt8(3)
comptime JSON_STRING = UInt8(4)
comptime JSON_ARRAY = UInt8(5)
comptime JSON_OBJECT = UInt8(6)