json
std/json — reading and writing JSON.
Written in Kite, on top of the five string primitives the language has and text.from_code. It is the first substantial body of Kite code in the standard library, and a parse returns (Json, error) like anything else that can fail: a malformed document is a value to handle, not something thrown.
Escapes are RFC 8259 §7, both ways. \uXXXX is decoded, including a surrogate pair as the one character it denotes, and every control character is escaped on the way out. Neither used to be true: caf\u00e9 decoded to cafu00e9 — silently, so a name simply came out wrong — and a carriage return went out raw, which is not JSON and which JSON.parse refuses with Bad control character in string literal. The decoding needed text.from_code, which was added for this and for std/toml; only std/toml picked it up.
Jsonparsestringifyprettyfieldattextnumber_ofint_ofbool_ofitemsentriesis_nullEncodetext_orint_orbool_or
Json
enum Json
A JSON value.
Recursive with no boxing annotation, because every Kite aggregate is already a GC reference.
NullBool(bool)Number(float)Text(str)Array([Json])Object({ str: Json })
parse
pub fn parse(input: str) -> (Json, error)
The value a document holds, or an error saying where it went wrong.
stringify
pub fn stringify(value: Json) -> str
A value as compact JSON.
pretty
pub fn pretty(value: Json) -> str
A value as indented JSON, for something a person will read.
field
pub fn field(value: Option<Json>, key: str) -> Option<Json>
A field of an object.
Every accessor takes an optional value and yields one, which is what makes them chain: json.field(json.field(doc, "a"), "b") reads left to right and yields nil the moment anything is missing. A plain Json is accepted wherever an Option<Json> is wanted, so the first call in a chain needs nothing special.
Kite has no ?., and this is why it does not need one: an operation that might find nothing says so in its result type, and the branch is taken once at the end rather than hidden at every step.
at
pub fn at(value: Option<Json>, index: int) -> Option<Json>
text
pub fn text(value: Option<Json>) -> Option<str>
number_of
pub fn number_of(value: Option<Json>) -> Option<float>
int_of
pub fn int_of(value: Option<Json>) -> Option<int>
bool_of
pub fn bool_of(value: Option<Json>) -> Option<bool>
items
pub fn items(value: Option<Json>) -> [Json]
The elements of an array, or nothing at all — a caller iterating them wants a slice rather than a branch.
entries
pub fn entries(value: Option<Json>) -> { str: Json }
An object's entries, in the order the document wrote them.
The counterpart to items for the other container. Anything that is not an object yields nothing rather than an error, which is what makes the accessors chain: a caller that needs to tell "not an object" from "an empty object" matches on the Json itself, which is still there.
is_null
pub fn is_null(value: Option<Json>) -> bool
Whether a document says nothing here.
A field that is absent and a field written null both answer true, and that is the point: the two mean the same thing to every producer of JSON, and a reader that told them apart would be reading a distinction the format does not reliably carry. @derive(Decode) uses this for an Option<T> field.
Encode
trait Encode
A value that can become JSON.
Declared here rather than in the prelude because it mentions Json, and a trait cannot be declared somewhere that has never heard of the type it returns. @derive(Encode) writes the body; the decoding direction is an associated function on the type — User.decode(doc) — because a trait method cannot say it returns the implementing type.
fn encode(self) -> Json
text_or
pub fn text_or(value: Option<Json>, key: str, fallback: str) -> str
A field's text, or a fallback — the shape most configuration reading takes.
int_or
pub fn int_or(value: Option<Json>, key: str, fallback: int) -> int
bool_or
pub fn bool_or(value: Option<Json>, key: str, fallback: bool) -> bool