JSON
Strict JSON decoding, typed decode, mutable DOM values, token input, and streaming output in std.json.
std.json provides strict JSON decoding, typed decoding for selected Zynx
types, mutable DOM values, a token decoder for io.Reader inputs, one-shot
encoding, and a small streaming output encoder.
In-tree tools using this surface include examples/manifest-inspect,
examples/jsoncheck, and examples/jsonset.
The implementation currently uses a vendored JSON backend internally. That
backend is not part of the public API: callers own and pass json.Value
values, not backend pointers or parser flags.
json.decode(text) accepts strict RFC-style JSON. Comments and trailing commas
are rejected. Input must be valid UTF-8. Parsed strings are returned as Zynx
String values, so decoded strings that violate the Zynx text invariant, such
as embedded NUL bytes, report JsonError.Invalid when extracted.
json.decode<T>(text) decodes directly into typed Zynx values. Supported
targets are bool, integer and floating scalar types, String, json.Value,
nullable values, Array<T>, and structs marked with @derive(json).
str is not a typed decode target; use owned String for decoded text.
JSON struct decoding is strict by default. Unknown object fields are rejected
unless the struct is marked @json_allow_unknown.
json.Value is an owned mutable DOM handle. Object and array mutation changes
the parent value. Previously returned child handles remain valid handles to the
old value they referenced.
JSON numbers are validated by the parser and stored as JSON number text.
Value.number() returns that text as a String. json.encode supports
Value, str, String, bool, integer scalars through 64-bit and
pointer-sized widths, f32, and f64. Floating-point NaN and infinity are
rejected as JsonError.Invalid.
JsonError.Invalid reports malformed JSON, invalid JSON number text,
unsupported non-finite floats, or invalid internal text extraction.
JsonError.Type reports a value of the wrong JSON kind. JsonError.Missing
reports a missing object key or out-of-range array/object index.
JsonError.State reports invalid streaming encoder/decoder state or invalid
DOM mutation shape. Allocation failure is reported as AllocError.
import std.json;
fn main() {
let doc = try json.decode("\x7b\"name\":\"app\",\"deps\":[\"util\"]\x7d");
let name = try doc.string("name");
assert name.repr() == "app";
let deps = try doc.array("deps");
assert try deps.len() == 1;
let first = try (try deps[0]).string();
assert first.repr() == "util";
let out = try json.object();
try (out["name"] = "app");
try (out["deps"] = &deps);
assert (try json.encode(&out)).repr() == "\x7b\"name\":\"app\",\"deps\":[\"util\"]\x7d";
}
Expected output: none. The assertions pass silently.
import std.json;
import {
Array
} from std.collections.array;
import {
String
} from std.string;
@derive(json)
struct Package {
@json_key("packageName") name: String,
version: u16 = 1,
tags: Array<String>,
@json_optional note: String,
}
fn main() {
let pkg = try json.decode<Package>("\x7b\"packageName\":\"zynx\",\"tags\":[\"compiler\"]\x7d");
assert pkg.name.str() == "zynx";
assert pkg.version == 1;
assert pkg.tags.length == 1;
assert pkg.note.str() == "";
}
Expected output: none. The assertions pass silently.
Typed struct attributes:
| Attribute | Target | Meaning |
|---|---|---|
@derive(json) | struct | Enables typed JSON decoding for the struct. |
@json_allow_unknown | struct | Allows unmapped object fields. |
@json_key("name") | field | Uses a different JSON object key. |
@json_optional | field | Allows the field to be absent and keeps the field default. |
@json_skip | field | Ignores the field during typed decode. |
Absent nullable fields default to null. Absent fields with explicit defaults
use that default. Absent String and Array<T> fields marked
@json_optional default to empty values.
json.Decoder<R: io.Reader> reads a JSON document from an io.Reader and
yields semantic json.Token values. The first implementation validates and
walks a DOM internally; the token API is the public contract.
import std.bytes;
import std.io;
import std.json;
fn main() {
let stream = try io.MemoryStream(bytes.Bytes("\x7b\"ok\":true\x7d"));
let dec = try json.Decoder<io.MemoryStream>(&stream);
match try dec.next() {
.BeginObject => {},
_ => { assert false; },
}
match try dec.next() {
.Key(key) => { assert key.str() == "ok"; },
_ => { assert false; },
}
match try dec.next() {
.Bool(value) => { assert value; },
_ => { assert false; },
}
match try dec.next() {
.EndObject => {},
_ => { assert false; },
}
match try dec.next() {
.Eof => {},
_ => { assert false; },
}
try dec.finish();
}
Expected output: none. The assertions pass silently.
import std.io;
import std.json;
import { String } from std.string;
fn main() {
let stream = io.MemoryStream();
let enc = json.Encoder<io.MemoryStream>(&stream);
try enc.begin_object();
try enc.field("ok", true);
try enc.key("items");
try enc.begin_array();
try enc.value(1);
try enc.value("two");
try enc.end_array();
try enc.end_object();
try enc.finish();
let text = try String(stream.bytes());
assert text.repr() == "\x7b\"ok\":true,\"items\":[1,\"two\"]\x7d";
}
Expected output: none. The assertion passes silently.
| Symbol | Signature | Notes |
|---|---|---|
JsonError | error | Invalid, Type, Missing, and State. |
Value | struct | Owned mutable JSON DOM value handle. |
Token | enum | Streaming decoder token: BeginObject, EndObject, BeginArray, EndArray, Key(String), String(String), Number(String), Bool(bool), Null, or Eof. |
Decoder<R: io.Reader> | struct | Token decoder over a borrowed reader. |
Encoder<W: io.Writer> | struct | Streaming JSON output encoder over a borrowed writer. |
decode | decode(text: str) throws(JsonError | AllocError) -> Value | Decodes strict JSON text into an owned mutable DOM value. |
decode<T> | decode<T>(text: str) throws(JsonError | AllocError) -> T | Decodes into a supported scalar, String, json.Value, nullable value, Array<T>, or @derive(json) struct. |
null | null() throws(JsonError | AllocError) -> Value | Creates a JSON null value. |
boolean | boolean(value: bool) throws(JsonError | AllocError) -> Value | Creates a JSON boolean value. |
string | string(value: str) throws(JsonError | AllocError) -> Value | Creates a JSON string value. |
number | number(value: str/integer/f32/f64) throws(JsonError | AllocError) -> Value | Creates a JSON number from validated text or scalar input. |
array | array() throws(AllocError) -> Value | Creates an empty JSON array. |
object | object() throws(AllocError) -> Value | Creates an empty JSON object. |
encode | encode(value) throws(JsonError | AllocError) -> String | Encodes a Value, text, bool, integer, f32, or f64 as strict JSON text. |
| Method | Result |
|---|---|
kind() | Internal kind code; prefer typed predicates and accessors. |
is_null(), is_bool(), is_number(), is_string(), is_array(), is_object() | Boolean kind checks. |
object(), array() | Retain and return this value when it has the requested kind. |
string() | Copy a JSON string into a Zynx String. |
number() | Copy a JSON number's validated source text into a String. |
bool() | Return a JSON boolean. |
encode() | Encode this value as JSON text. |
get(key), [](key) | Get an object member by key. |
[](index), index(index) | Get an array item by index. |
object(key), array(key), string(key), number(key), bool(key) | Get an object member and require the requested kind. |
len() | Return array length or object member count. |
keys() | Copy all object keys into an array. |
key(index) | Copy the object key at insertion order index. |
put(key, value), push(value), set(index, value) | Mutate objects and arrays with Value, text, bool, integer, f32, or f64 inputs. |
[]=(key, value), []=(index, value) | Indexed assignment forms for object members and array items. |
| Method | Result |
|---|---|
begin_object(), end_object() | Enter or leave an object context. |
begin_array(), end_array() | Enter or leave an array context. |
key(key) | Write an object key and colon; the next call must write the value. |
value(value) | Write a scalar or Value in the current context. |
field(key, value) | Write an object key and value pair. |
finish() | Verify that one complete document was written and all contexts are closed. |
| Method | Result |
|---|---|
next() | Return the next semantic json.Token. |
skip_value() | Consume the next complete value, including nested arrays or objects. |
finish() | Verify that the decoder reached Token.Eof. |