///|
fn json_output_at(
value : Value,
budget : Budget,
depth : Int,
) -> Json raise XdrError {
budget.visit(depth, 0)
match value {
VVoid => Json::null()
VInt(n) | VEnum(n) => n.to_json()
VUInt(n) => n.to_json()
VHyper(n) => Json::string(n.to_string())
VUHyper(n) => Json::string(n.to_string())
VBool(b) => b.to_json()
VFloat(f) => {
let n = f.to_double()
if n.is_nan() || n.is_inf() {
raise Invalid(0, "nonfinite float has no JSON representation")
}
n.to_json()
}
VDouble(n) => {
if n.is_nan() || n.is_inf() {
raise Invalid(0, "nonfinite double has no JSON representation")
}
n.to_json()
}
VString(s) => Json::string(s)
VOpaque(bytes) => Json::string(to_hex(bytes))
VArray(items) => {
let out : Array[Json] = []
for item in items {
out.push(json_output_at(item, budget, depth + 1))
}
Json::array(out)
}
VOptional(None) => Json::null()
VOptional(Some(item)) =>
Json::object({ "some": json_output_at(item, budget, depth + 1) })
VStruct(fields) => {
let out : Map[String, Json] = Map([])
for pair in fields {
if out.contains(pair.0) {
raise Invalid(0, "duplicate record member")
}
out[pair.0] = json_output_at(pair.1, budget, depth + 1)
}
Json::object(out)
}
VUnion(tag, item) =>
Json::object({
"tag": tag.to_json(),
"value": json_output_at(item, budget, depth + 1),
})
}
}
///|
/// Binary validation precedes JSON output, including ASCII, collection and total byte limits.
pub fn to_json(
schema : Schema,
type_name : String,
value : Value,
) -> Json raise XdrError {
ignore(encode(schema, type_name, value))
let budget : Budget = {
left: schema.limits.max_items,
limits: schema.limits,
}
json_output_at(value, budget, 0)
}