///|
/// Convert JsonValue to JSON string
pub fn stringify(value : JsonValue) -> String {
let buf = @buffer.new()
write_value(buf, value)
buf.to_string()
}
///|
/// Write JSON value to buffer
fn write_value(buf : @buffer.Buffer, value : JsonValue) -> Unit {
match value {
Null => buf.write_string("null")
Bool(true) => buf.write_string("true")
Bool(false) => buf.write_string("false")
Number(n) =>
// Handle special cases
if n.is_nan() {
buf.write_string("null")
} else if n.is_inf() {
buf.write_string("null")
} else {
buf.write_string(n.to_string())
}
String(s) => write_string(buf, s)
Array(arr) => write_array(buf, arr)
Object(obj) => write_object(buf, obj)
}
}
///|
/// Write JSON string with escaping
fn write_string(buf : @buffer.Buffer, s : String) -> Unit {
buf.write_string("\"")
for ch in s {
match ch {
'"' => buf.write_string("\\\"")
'\\' => buf.write_string("\\\\")
'\b' => buf.write_string("\\b")
'\u000C' => buf.write_string("\\f")
'\n' => buf.write_string("\\n")
'\r' => buf.write_string("\\r")
'\t' => buf.write_string("\\t")
ch if ch >= '\u0000' && ch <= '\u001F' => {
// Control characters as unicode escape
buf.write_string("\\u00")
let code = ch.to_int()
let hex = "0123456789abcdef"
buf.write_char(hex.get_char(code / 16).unwrap())
buf.write_char(hex.get_char(code % 16).unwrap())
}
ch => buf.write_char(ch)
}
}
buf.write_string("\"")
}
///|
/// Write JSON array
fn write_array(buf : @buffer.Buffer, arr : Array[JsonValue]) -> Unit {
buf.write_string("[")
for i, value in arr {
if i > 0 {
buf.write_string(",")
}
write_value(buf, value)
}
buf.write_string("]")
}
///|
/// Write JSON object
fn write_object(buf : @buffer.Buffer, obj : Map[String, JsonValue]) -> Unit {
buf.write_string("{")
let mut first = true
for key, value in obj {
if not(first) {
buf.write_string(",")
}
first = false
write_string(buf, key)
buf.write_string(":")
write_value(buf, value)
}
buf.write_string("}")
}
///|
/// Pretty print with indentation
pub fn stringify_pretty(value : JsonValue, indent : Int) -> String {
let buf = @buffer.new()
write_value_pretty(buf, value, 0, indent)
buf.to_string()
}
///|
/// Write JSON value with pretty printing
fn write_value_pretty(
buf : @buffer.Buffer,
value : JsonValue,
depth : Int,
indent : Int,
) -> Unit {
match value {
Null => buf.write_string("null")
Bool(true) => buf.write_string("true")
Bool(false) => buf.write_string("false")
Number(n) =>
if n.is_nan() || n.is_inf() {
buf.write_string("null")
} else {
buf.write_string(n.to_string())
}
String(s) => write_string(buf, s)
Array(arr) => write_array_pretty(buf, arr, depth, indent)
Object(obj) => write_object_pretty(buf, obj, depth, indent)
}
}
///|
/// Write indentation
fn write_indent(buf : @buffer.Buffer, depth : Int, indent : Int) -> Unit {
for _i = 0; _i < depth * indent; _i = _i + 1 {
buf.write_string(" ")
}
}
///|
/// Write JSON array with pretty printing
fn write_array_pretty(
buf : @buffer.Buffer,
arr : Array[JsonValue],
depth : Int,
indent : Int,
) -> Unit {
buf.write_string("[")
if arr.is_empty() {
buf.write_string("]")
return
}
buf.write_string("\n")
for i, value in arr {
write_indent(buf, depth + 1, indent)
write_value_pretty(buf, value, depth + 1, indent)
if i < arr.length() - 1 {
buf.write_string(",")
}
buf.write_string("\n")
}
write_indent(buf, depth, indent)
buf.write_string("]")
}
///|
/// Write JSON object with pretty printing
fn write_object_pretty(
buf : @buffer.Buffer,
obj : Map[String, JsonValue],
depth : Int,
indent : Int,
) -> Unit {
buf.write_string("{")
let keys : Array[String] = []
for key, _ in obj {
keys.push(key)
}
if keys.is_empty() {
buf.write_string("}")
return
}
buf.write_string("\n")
for i, key in keys {
write_indent(buf, depth + 1, indent)
write_string(buf, key)
buf.write_string(": ")
write_value_pretty(buf, obj[key], depth + 1, indent)
if i < keys.length() - 1 {
buf.write_string(",")
}
buf.write_string("\n")
}
write_indent(buf, depth, indent)
buf.write_string("}")
}