Tin provides JSON encoding and decoding through stdlib/json.
No extra linker flags are required. The json stdlib uses only libc and the Tin runtime.
use jsonjson::encode[T](v T) string serialises any Tin value to a JSON string.
T may be a primitive type (bool, i64, f64), string, struct, or tuple.
json::encode(42 as i64) // "42"
json::encode(true) // "true"
json::encode(false) // "false"
json::encode("hello") // "\"hello\""
json::encode("say \"hi\"") // "\"say \\\"hi\\\"\""Struct fields are encoded using compile-time reflection. By default the field name is used as the JSON key:
struct point =
x i64
y i64
json::encode(point{x: 3, y: 4}) // "{\"x\":3,\"y\":4}"Nested structs are encoded recursively. The phantom type parameter T on the
internal _encode_any[T] helper forces the field dispatch tables to be built
at the call site (the user's module), giving the encoder access to all
user-defined struct types at any nesting depth:
struct rect =
origin point
size point
json::encode(rect{origin: point{x:0, y:0}, size: point{x:100, y:50}})
// {"origin":{"x":0,"y":0},"size":{"x":100,"y":50}}Tuples are encoded as JSON objects with alphabetical field names (a, b,
c, ...):
json::encode((10, "hello")) // "{\"a\":10,\"b\":\"hello\"}"
json::encode((1, true, 3.14)) // "{\"a\":1,\"b\":true,\"c\":3.14}"Add a @"json:..." tag to control how a field appears in JSON:
struct user =
id i64 @"json:user_id" // rename key
email string @"json:email_address" // rename key
pwd string @"json:-" // omit field entirely
json::encode(user{id: 1, email: "a@b.com", pwd: "secret"})
// {"user_id":1,"email_address":"a@b.com"}| Tag | Effect |
|---|---|
@"json:name" |
Use name as the JSON key |
@"json:-" |
Omit this field from the output |
| (no tag) | Use the Tin field name unchanged |
json::parse(s string) Value parses a JSON string into a dynamic Value tree.
Use this when the JSON structure is not known at compile time.
let v = json::parse("{\"name\":\"alice\",\"age\":30}")
v.get("name").as_string() // "alice"
v.get("age").as_int() // 30v.is_null() // true for JSON null
v.is_bool()
v.is_int()
v.is_float()
v.is_string()
v.is_array()
v.is_object()v.as_bool() // bool
v.as_int() // i64
v.as_float() // f64
v.as_string() // stringlet obj = json::parse("{\"x\":1,\"y\":2}")
// Get value by key (returns null Value if missing):
obj.get("x").as_int() // 1
obj.get("missing").is_null() // true
// Iterate all keys:
let keys = obj.keys() // [string]
for let k string in keys:
echo "{k}: {obj.get(k).as_int()}"let arr = json::parse("[10,20,30]")
arr.array_len() // 3
arr.index(0).as_int() // 10
arr.index(1).as_int() // 20
arr.index(99).is_null() // true - out of bounds returns nulljson::parse[T](s string) T decodes JSON directly into a struct T using
compile-time reflection. This is more convenient than untyped parsing when the
JSON schema is fixed at compile time.
struct point =
x i64
y i64
let p = json::parse[point]("{\"x\":3,\"y\":4}")
echo p.x // 3
echo p.y // 4Field tags work the same way as for encoding:
struct api_user =
id i64 @"json:user_id"
name string @"json:display_name"
let u = json::parse[api_user]("{\"user_id\":7,\"display_name\":\"bob\"}")
echo u.id // 7
echo u.name // "bob"Unknown JSON keys are silently ignored. Missing JSON keys leave the corresponding struct field at its zero value.
Nested struct fields are decoded recursively:
struct rect =
origin point
size point
let r = json::parse[rect]("{\"origin\":{\"x\":3,\"y\":4},\"size\":{\"x\":100,\"y\":50}}")
echo r.origin.x // 3
echo r.size.y // 50Typed parsing maps JSON values to Tin types as follows:
| JSON type | Tin field types |
|---|---|
number (integer) |
i64, i32, i16, i8 (truncated), f64 (promoted) |
number (float) |
f64; i64 (truncated) |
bool |
bool |
string |
string |
null |
(field left at zero value) |
object |
nested struct (decoded recursively) |
| Function / Method | Description |
|---|---|
json::encode(v) |
Encode any Tin value to a JSON string (primitives, structs, tuples) |
json::parse(s) |
Parse JSON into an untyped Value tree |
json::parse[T](s) |
Parse JSON directly into struct T (flat structs with primitive fields) |
v.is_null() / v.is_int() / ... |
Kind checks on Value |
v.as_bool() / v.as_int() / ... |
Type accessors on Value |
v.get(key) |
Look up key in a JSON object Value |
v.keys() |
All keys in a JSON object Value |
v.index(i) |
Element i of a JSON array Value |
v.array_len() |
Number of elements in a JSON array Value |