json
A complete RFC 8259 value model, parser, and serializer. Not auto-imported.
import std::json;
match (parse(source)) {
Result::Ok(doc) => {
match (doc.get(Str::new("port"))) {
Option::Some(v) => { /* v: JsonValue* */ }
Option::None => { /* absent */ }
}
}
Result::Err(e) => {
eprintln(f"{e.line}:{e.column}: {e.describe()}");
}
}
| Item | Import |
|---|---|
JsonValue, JsonNumber, JsonObject | import std::json::value; |
parse, MAX_DEPTH | import std::json::parser; |
stringify, stringify_pretty, write_value | import std::json::serializer; |
JsonError, JsonErrorKind | import std::json::error; |
JsonValue
A tagged union over the six JSON types. It is recursive through Array<JsonValue> and JsonObject, each owning variant holds heap storage, and drop frees the tree recursively.
type enum JsonValue {
Null;
Bool(boolean);
Number(JsonNumber);
String(String);
Array(Array<JsonValue>);
Object(JsonObject);
}
Constructing
| Constructor | Produces |
|---|---|
static null_value() | Null |
static bool_value(b: boolean) | Bool |
static int_value(n: i64) | Number(Int) |
static uint_value(n: u64) | Number(UInt) |
static float_value(n: f64) | Number(Float) |
static string_value(s: String) | String, taking ownership |
static from<T>(src: T) | Compile-time dispatch over the scalar types |
static string_array(items: &string[]) | Array of strings |
static empty_array() / empty_object() |
Inspecting
is_null, is_bool, is_number, is_string, is_array, and is_object each return boolean.
| Method | Returns | Notes |
|---|---|---|
get(key: Str) | Option<JsonValue*> | Object member lookup, O(1) average. |
at(index: u64) | Option<JsonValue*> | Array element. |
length() | u64 | Elements of an array, members of an object. |
as<T>() | Option<T> | Typed extraction, where T: TryFrom<&JsonValue>. |
TryFrom<&JsonValue> is implemented for boolean, i64, u64, f64, and Str, so as<T>() covers the usual extractions:
const port: Option<i64> = doc.get(Str::new("port")).unwrap_ptr().as<i64>();
JsonNumber
JSON has one number type; this splits it by source representation so integers round-trip exactly — 42 parses and re-serializes as 42, not 42.0.
type enum JsonNumber { Int(i64); UInt(u64); Float(f64); }
Int covers signed values fitting i64, UInt carries values in (i64::MAX, u64::MAX], and everything else — decimals, exponents — is Float. Lossy conversion is opt-in: as_i64() returns None for a UInt beyond i64::MAX or a Float with a fractional component, and as_f64() gives the lossy view when you want it.
JsonObject
Object access is O(1) on average through a hash index, and insertion order is preserved in a parallel keys array, so serialization is deterministic.
| Method | Notes |
|---|---|
static new() / with_capacity(capacity: u64) | |
length() / is_empty() | |
insert(key: String, value: JsonValue) | Takes ownership of both. |
put(key: string, value: JsonValue) | Convenience over a C string literal. |
get(key: Str) | Option<JsonValue*> |
contains(key: Str) | boolean |
key_at(index: u64) / value_at(index: u64) | Insertion-ordered access. |
Parsing
parse(text: Str) -> Result<JsonValue, JsonError> parses a complete document. Trailing whitespace is fine; trailing anything else is TrailingData.
The parser is single-pass recursive descent over a borrowed Str, and it is RFC 8259 strict: no trailing commas, no unquoted keys, no comments. String literals decode \X and \uXXXX escapes, and UTF-16 surrogate pairs are recombined; a lone surrogate is InvalidUnicode.
MAX_DEPTH caps combined object and array nesting at 256. The default is generous for hand-authored data and tight enough that a malicious megabyte of [[[...]]] cannot exhaust the stack.
Serializing
| Function | Notes |
|---|---|
stringify(v: &JsonValue) -> String | Compact — no whitespace between tokens. |
stringify_pretty(v: &JsonValue) -> String | Two-space indent, one entry per line. |
write_value(out: mut &String, v: &JsonValue) | Append compact output to a string you own. |
write_pretty(out: mut &String, v: &JsonValue) | Append pretty output. |
The write_* forms exist so several values can be concatenated into one buffer without intermediate allocations. Empty objects and arrays stay on a single line even in pretty mode.
String output escapes per the spec: UTF-8 bytes outside the ASCII control range pass through, and bytes below 0x20 are emitted as \uXXXX.
The serializer mirrors the parser's depth cap, so a parsed tree always round-trips; only a programmatically built tree deeper than 256 is bounded, and that is there to stop unbounded recursion on adversarial input.
JsonError
Modelled as a kind plus a position plus a message. Branch on kind for programmatic decisions; msg carries the human-readable detail.
| Field / method | Notes |
|---|---|
kind | JsonErrorKind — the closed set of parser failures. |
line / column | 1-indexed, matching editor conventions. |
offset | 0-indexed byte offset into the source. |
msg | Owned String with the detail. |
describe() | Str — the standard accessor every stdlib error exposes. |
JsonErrorKind::label() gives a short diagnostic slug: "unexpected_eof", "invalid_number", and so on.
JsonError owns its message, so it carries a drop.