7.2. Boost package for JSON
The JSON_BOOST module extends JSON support with operator overloads for convenient
field access (?[]), null-coalescing (??), and automatic struct-to-JSON
conversion macros (from_JsValue, to_JsValue).
See also JSON manipulation library for core JSON parsing and writing. See JSON for a hands-on tutorial.
All functions and symbols are in “json_boost” module, use require to get access to it.
require daslib/json_boost
Example:
require daslib/json_boost
[export]
def main() {
let data = "\{ \"name\": \"Alice\", \"age\": 30 \}"
var error = ""
var js <- read_json(data, error)
if (error == "") {
let name = js?.name ?? "?"
print("name = {name}\n")
let age = js?.age ?? -1
print("age = {age}\n")
}
unsafe {
delete js
}
}
// output:
// name = Alice
// age = 30
7.2.1. Field annotations
Struct fields can carry annotations that control how JV / from_JV and
the builtin sprint_json serialize and deserialize them. Annotations are
parsed by parse_json_annotation
into a JsonFieldState and stored in a
static_let cache so each field is parsed only once.
sprint_json requires options rtti for annotations to take effect at
runtime.
Annotation |
Effect |
|---|---|
|
Skip the field when its value is default / empty ( |
|
Use json_key instead of the daslang field name in JSON output and
when looking up keys during |
|
Treat a |
|
Write the string field without escaping special characters (backslashes, quotes, etc.). |
|
Serialize an enum field as its integer value instead of the enumeration name string. |
Example with sprint_json:
options rtti
struct Config {
name : string
@optional debug : bool // omitted when false
@rename="type" _type : string // JSON key is "type"
@embed raw : string // embedded as raw JSON
@unescape path : string // no escaping of backslashes
@enum_as_int level : Priority // integer, not string
}
let json_str = sprint_json(cfg, false)
See JSON for runnable examples of every annotation.
7.2.1.1. Structures
- JsonFieldState
Per-field serialization options for JSON struct conversion.
- Fields:
argName : string - name of the field in JSON
enumAsInt : bool - whether to parse enum as integer
unescape : bool - whether to unescape strings
embed : bool - whether to embed the field
optional : bool - whether the field is optional
7.2.1.2. Reader macros
- json
This macro implements embedding of the JSON object into the program:
var jsv = %json~
{
"name": "main_window",
"value": 500,
"size": [1,2,3]
} %%
7.2.1.3. Variant macros
- better_json
This macro is used to implement is json_value and as json_value runtime checks. It essentially substitutes value as name with value.value as name and value is name with value.value is name.
7.2.1.4. Value conversion
JV (val1: auto; val2: auto; val3: auto; val4: auto) : JsonValue?
JV (val1: auto; val2: auto; val3: auto; val4: auto; val5: auto) : JsonValue?
JV (val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto) : JsonValue?
JV (val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto; val7: auto) : JsonValue?
from_JV (v: JsonValue const?; anything: table<auto(KT), auto(VT)>) : auto
from_JV (v: JsonValue const?; ent: auto(EnumT); defV: EnumT = EnumT()) : EnumT
from_JV (v: JsonValue const?; ent: auto(VecT); defV: VecT = VecT()) : auto
from_JV (v: JsonValue const?; ent: bitfield16:uint16<>; defV: bitfield16 = bitfield16()) : auto
from_JV (v: JsonValue const?; ent: bitfield64:uint64<>; defV: bitfield64 = bitfield64()) : auto
from_JV (v: JsonValue const?; ent: bitfield8:uint8<>; defV: bitfield8 = bitfield8()) : auto
from_JV (v: JsonValue const?; ent: bitfield; defV: bitfield = bitfield()) : auto
from_JV (v: JsonValue const?; ent: bool; defV: bool = false) : auto
from_JV (v: JsonValue const?; ent: double; defV: double = 0lf) : auto
from_JV (v: JsonValue const?; ent: float; defV: float = 0f) : auto
from_JV (v: JsonValue const?; ent: int16; defV: int16 = int16(0)) : auto
from_JV (v: JsonValue const?; ent: int64; defV: int64 = 0) : auto
from_JV (v: JsonValue const?; ent: int8; defV: int8 = int8(0)) : auto
from_JV (v: JsonValue const?; ent: int; defV: int = 0) : auto
from_JV (v: JsonValue const?; ent: string; defV: string = “”) : auto
from_JV (v: JsonValue const?; ent: uint16; defV: uint16 = uint16(0)) : auto
from_JV (v: JsonValue const?; ent: uint64; defV: uint64 = 0x0) : auto
from_JV (v: JsonValue const?; ent: uint8; defV: uint8 = uint8(0)) : auto
from_JV (v: JsonValue const?; ent: uint; defV: uint = 0x0) : auto
7.2.1.4.1. JV
- JV(v: auto(VecT) ): auto
Creates JsonValue out of value.
- Arguments:
v : auto(VecT)
- JV(val1: auto; val2: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto; val7: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto; val7: auto; val8: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto; val7: auto; val8: auto; val9: auto ): JsonValue?
- JV(val1: auto; val2: auto; val3: auto; val4: auto; val5: auto; val6: auto; val7: auto; val8: auto; val9: auto; val10: auto ): JsonValue?
- JV(value: auto(TT) ): JsonValue?
7.2.1.4.2. from_JV
- from_JV(v: JsonValue const?; anything: auto(TT) ): auto
Parse a JSON value and return the corresponding value of any type. This is the main dispatch function that handles various types.
- Arguments:
v : JsonValue?
anything : auto(TT)
- from_JV(v: JsonValue const?; anything: table<auto(KT), auto(VT)> ): auto
- from_JV(v: JsonValue const?; ent: auto(EnumT); defV: EnumT = EnumT() ): EnumT
- from_JV(v: JsonValue const?; ent: auto(VecT); defV: VecT = VecT() ): auto
- from_JV(v: JsonValue const?; ent: bitfield16:uint16<>; defV: bitfield16 = bitfield16() ): auto
- from_JV(v: JsonValue const?; ent: bitfield64:uint64<>; defV: bitfield64 = bitfield64() ): auto
- from_JV(v: JsonValue const?; ent: bitfield8:uint8<>; defV: bitfield8 = bitfield8() ): auto
- from_JV(v: JsonValue const?; ent: bitfield; defV: bitfield = bitfield() ): auto
- from_JV(v: JsonValue const?; ent: bool; defV: bool = false ): auto
- from_JV(v: JsonValue const?; ent: double; defV: double = 0lf ): auto
- from_JV(v: JsonValue const?; ent: float; defV: float = 0f ): auto
- from_JV(v: JsonValue const?; ent: int16; defV: int16 = int16(0) ): auto
- from_JV(v: JsonValue const?; ent: int64; defV: int64 = 0 ): auto
- from_JV(v: JsonValue const?; ent: int8; defV: int8 = int8(0) ): auto
- from_JV(v: JsonValue const?; ent: int; defV: int = 0 ): auto
- from_JV(v: JsonValue const?; ent: string; defV: string = "" ): auto
- from_JV(v: JsonValue const?; ent: uint16; defV: uint16 = uint16(0) ): auto
- from_JV(v: JsonValue const?; ent: uint64; defV: uint64 = 0x0 ): auto
- from_JV(v: JsonValue const?; ent: uint8; defV: uint8 = uint8(0) ): auto
- from_JV(v: JsonValue const?; ent: uint; defV: uint = 0x0 ): auto
7.2.1.5. LINQ source builders
- from_json(jv: JsonValue const?; t: type<auto(TT) const> ): iterator<TT>
Lazily walks the elements of a JSON array jv, reading each element’s top-level fields by name
into a TT — the JSON counterpart of from_xml_node, for for loops and LINQ chains:
for (car in from_json(jv, type<Car>)) { ... }. A non-array (or null) jv yields nothing; rows
collected via to_array or a comprehension stay valid. It is a flat-object query source: it
reads fields by name and does not honor a custom whole-row from_JV override for TT (field
values still convert via from_JV). If you need a row-level from_JV override, materialize to
an array first — [for (e in jv.value as _array); from_JV(e, type<TT>)] — and query that.
- Arguments:
jv : JsonValue?
t : auto(TT)
- from_json_row(jv: JsonValue const?; t: auto(TT) ): TT
Materialize one JSON object into TT by name — the per-element worker behind from_json.
A struct reads each field by name (recursively); the basic value types (string / bool / numeric)
are read straight off the JsValue variant here, skipping the from_JV scalar wrapper that
every fused field read would otherwise pay per element. Only enum / array / tuple / variant / custom
handled types still delegate to from_JV. Never invokes a whole-struct from_JV override.
Precondition: jv is a non-null pointer (a JSON null value is fine — that is a non-null pointer
with a _null tag); both callers (read_json_field / the from_json generator) guarantee it,
so the inline reads skip the null-pointer guard. t is a type witness (unused).
- Arguments:
jv : JsonValue?
t : auto(TT)
- read_json_field(jv: JsonValue const?; key: string; defv: auto(TT) ): TT
Reads one same-named key of the JSON object jv into a TT — the field-pruned counterpart of
a full by-name materialize, emitted by linq_fold’s fused JSON lane. A missing key keeps defv
(pass the struct field’s declared default). The value is converted by name via from_json_row,
so a struct field reads its fields by name too — never an overridable whole-struct from_JV.
jv is const so the fused loop’s jsrc as _array elements (const) bind without a copy.
[constant_expression(key=false)]: when key is a string literal (the fused lane always emits
one — and from_json_row’s apply_imm substitutes the field name as one) it is folded into a
specialized copy, so the ?[key] lookup bakes the key hash at simulate time
(SafeTableIndex_WithHash); a runtime key falls back to the generic.
- Arguments:
jv : JsonValue?
key : string
defv : auto(TT)
7.2.1.6. Element access operators
JsonValue const? ==const?. (a: JsonValue const? ==const; key: string) : JsonValue?
JsonValue const? ==const?[] (a: JsonValue const? ==const; idx: int) : JsonValue?
JsonValue const? ==const?[] (a: JsonValue const? ==const; key: string) : JsonValue?
JsonValue? ==const?. (var a: JsonValue? ==const; key: string) : JsonValue?
JsonValue? ==const?[] (var a: JsonValue? ==const; idx: int) : JsonValue?
JsonValue? ==const?[] (var a: JsonValue? ==const; key: string) : JsonValue?
- JsonValue const? ==const?.(a: JsonValue const? ==const; key: string ): JsonValue?
Returns the value of the key in the JSON object, if it exists.
- Arguments:
a : JsonValue?!
key : string
7.2.1.6.1. JsonValue const? ==const?[]
- JsonValue const? ==const?[](a: JsonValue const? ==const; idx: int ): JsonValue?
Returns the value of the index in the JSON array, if it exists.
- Arguments:
a : JsonValue?!
idx : int
- JsonValue const? ==const?[](a: JsonValue const? ==const; key: string ): JsonValue?
- JsonValue? ==const?.(a: JsonValue? ==const; key: string ): JsonValue?
Returns the value of the key in the JSON object, if it exists.
- Arguments:
a : JsonValue?!
key : string
7.2.1.6.2. JsonValue? ==const?[]
- JsonValue? ==const?[](a: JsonValue? ==const; idx: int ): JsonValue?
Returns the value of the index in the JSON array, if it exists.
- Arguments:
a : JsonValue?!
idx : int
- JsonValue? ==const?[](a: JsonValue? ==const; key: string ): JsonValue?
7.2.1.7. Null coalescing operators
JsonValue const??? (a: JsonValue const?; val: double) : double
JsonValue const??? (a: JsonValue const?; val: float) : float
JsonValue const??? (a: JsonValue const?; val: int16) : int16
JsonValue const??? (a: JsonValue const?; val: int64) : int64
JsonValue const??? (a: JsonValue const?; val: string) : string
JsonValue const??? (a: JsonValue const?; val: uint16) : uint16
JsonValue const??? (a: JsonValue const?; val: uint64) : uint64
JsonValue const??? (a: JsonValue const?; val: uint8) : uint8
7.2.1.7.1. JsonValue const???
- JsonValue const???(a: JsonValue const?; val: bool ): bool
Returns the value of the JSON object, if it exists, otherwise returns the default value.
- Arguments:
a : JsonValue?
val : bool
- JsonValue const???(a: JsonValue const?; val: double ): double
- JsonValue const???(a: JsonValue const?; val: float ): float
- JsonValue const???(a: JsonValue const?; val: int ): int
- JsonValue const???(a: JsonValue const?; val: int16 ): int16
- JsonValue const???(a: JsonValue const?; val: int64 ): int64
- JsonValue const???(a: JsonValue const?; val: int8 ): int8
- JsonValue const???(a: JsonValue const?; val: string ): string
- JsonValue const???(a: JsonValue const?; val: uint ): uint
- JsonValue const???(a: JsonValue const?; val: uint16 ): uint16
- JsonValue const???(a: JsonValue const?; val: uint64 ): uint64
- JsonValue const???(a: JsonValue const?; val: uint8 ): uint8
7.2.1.8. Value extraction
- JsonValue const? ==const?.value(a: JsonValue const? ==const ): variant<_object:table<string;JsonValue?>;_array:array<JsonValue?>;_string:string;_number:double;_longint:int64;_bool:bool;_null:void?> const?
Returns the value of the JSON object, if it exists.
- Arguments:
a : JsonValue?!
- JsonValue? ==const?.value(a: JsonValue? ==const ): variant<_object:table<string;JsonValue?>;_array:array<JsonValue?>;_string:string;_number:double;_longint:int64;_bool:bool;_null:void?>?
Returns the value of the JSON object, if it exists.
- Arguments:
a : JsonValue?!
7.2.1.9. Annotation parsing
- parse_json_annotation(name: string; annotation: array<tuple<name:string;data:variant<tBool:bool;tInt:int;tUInt:uint;tInt64:int64;tUInt64:uint64;tFloat:float;tDouble:double;tString:string;nothing:any>>> ): JsonFieldState
Parse JSON field annotations and return the corresponding JsonFieldState.
- Arguments:
name : string
annotation : array<tuple<name:string;data: RttiValue>>