Alpha. Vary is under active development and not ready for production use. Syntax, APIs, performance, and behaviour may change between releases.
JSON
Namespace rule
import json gates access to the Json, JsonValue, JsonError, JsonReader,
and JsonStreamWriter types. Use type-static methods and instance methods:
import json
let j = Json.parse("{\"name\": \"Alice\"}").unwrap()
let text = j.stringify()
The compiler enforces the import: using Json.parse() without import json
is a compile error.
Tree API
Json.parse() returns a typed Result[Json, JsonError]:
let result = Json.parse("{\"name\": \"Alice\", \"age\": 30}")
if result.is_ok() {
let json = result.unwrap()
let name = json.get_str("name") # Str? "Alice"
let age = json.get_int("age") # Int? 30
}
Convenience accessors: get_str, get_int, get_float, get_bool, get_list.
Static methods
| Method | Returns | Description |
|---|---|---|
Json.parse(text) | Result[Json, JsonError] | Parse a JSON string |
Json.parse_bytes(b) | Result[Json, JsonError] | Parse UTF-8 bytes |
Json.from_str(s) | Json | Create a string value |
Json.from_int(i) | Json | Create an integer value |
Json.from_float(d) | Json | Create a float value |
Json.from_bool(b) | Json | Create a boolean value |
Json.null_value() | Json | Create a null value |
Json.empty_object() | Json | Create an empty mutable object |
Instance methods
| Method | Returns | Description |
|---|---|---|
.stringify() | Str | Compact JSON string |
.stringify_pretty() | Str | Indented JSON string |
.stringify_to_bytes() | Bytes | Compact JSON as UTF-8 bytes |
.get_path(path) | Json? | Dot-notation path access (e.g., "items.0.name") |
.require_path(path) | Result[Json, JsonError] | Path access with error context |
JSON Pointer (RFC 6901) navigates nested structures:
let json = Json.parse("{\"a\":{\"b\":[1,2,3]}}").unwrap()
let val = json.pointer_get("/a/b/1")
Require methods return Result[T, JsonError]:
let name = json.require_str("/user/name")
Streaming API
For large documents, use JsonReader for pull-based parsing and JsonStreamWriter for incremental building:
let reader = JsonReader.from_str('{"name":"Alice"}').unwrap()
let token = reader.next().unwrap()
reader.close()
let w = JsonStreamWriter.create()
w.begin_object()
w.key("name")
w.str_value("Alice")
w.end_object()
let json = w.finish()
Mutable building
Build JSON objects programmatically:
let obj = Json.empty_object()
obj.set_str("name", "Alice")
obj.set_int("age", 30)
obj.set_bool("active", True)
| Method | Returns | Description |
|---|---|---|
Json.empty_object() | Json | Create an empty mutable object |
.set_str(key, value) | Json | Set a string field |
.set_int(key, value) | Json | Set an integer field |
.set_bool(key, value) | Json | Set a boolean field |
.set_list(key, value) | Json | Set a list field |
.set(key, json) | Json | Set a nested Json value |
All setters return self for method chaining.
Typed decode DSL
For structured, validated JSON extraction, use Decoder (gated by import json). See JSON decode for the full reference.
import json
let node = json.decode("{\"name\": \"Alice\", \"age\": 30}")?
let name = node.field("name").str()? # Result[Str, DecodeError]
let age = node.field("age").int()? # Result[Int, DecodeError]
let role = node.field("role").str_or("guest") # Str (default if missing)
Navigate nested structures with chained .field() calls. Errors include the full
path (e.g., "config.db.port") and expected/actual types.
| Method | Description | Returns |
|---|---|---|
str() | Decode as string | Result[Str, DecodeError] |
int() | Decode as integer | Result[Int, DecodeError] |
float() | Decode as float | Result[Float, DecodeError] |
bool() | Decode as boolean | Result[Bool, DecodeError] |
object() | Decode as object | Result[Decoder, DecodeError] |
list() | Decode as list of nodes | Result[List[Decoder], DecodeError] |
enum(variants) | Decode as one of allowed strings | Result[Str, DecodeError] |
str_or_none() | String if present | Str? |
int_or_none() | Integer if present | Int? |
float_or_none() | Float if present | Float? |
bool_or_none() | Boolean if present | Bool? |
object_or_none() | Object if present | Decoder? |
list_or_none() | List if present | List[Decoder]? |
str_or(default) | String with fallback | Str |
int_or(default) | Integer with fallback | Int |
float_or(default) | Float with fallback | Float |
bool_or(default) | Boolean with fallback | Bool |
field(name) | Navigate to child field | Decoder |
at(index) | Navigate to list element | Result[Decoder, DecodeError] |
keys() | List object keys | List[Str] |
size() | Number of elements | Int |
path() | Current node path | Str |
validate_int(msg, check) | Validate integer with predicate | Result[Int, DecodeError] |
validate_str(msg, check) | Validate string with predicate | Result[Str, DecodeError] |
transform_str(fn) | Transform string value | Result[Str, DecodeError] |
DecodeError has .path(), .expected(), .actual(), and .message() methods.