//! JSON 序列化器——把 [`JsonValue`] 渲染回字符串。 //! JSON serializer — renders a [`JsonValue`] back to a String. use crate::value::JsonValue; use std::fmt::Write; /// 将 [`JsonValue`] 序列化为紧凑的 JSON 字符串。 /// Serialize a [`JsonValue`] to a compact JSON string. pub fn to_string(value: &JsonValue) -> String { let mut out = String::new(); write_value(value, &mut out); out } /// 把一个值写入 `out`(递归处理数组与对象)。 /// Write a value into `out` (recursing into arrays and objects). fn write_value(value: &JsonValue, out: &mut String) { match value { JsonValue::Null => out.push_str("null"), JsonValue::Bool(true) => out.push_str("true"), JsonValue::Bool(false) => out.push_str("false"), JsonValue::Num(n) => write_number(*n, out), JsonValue::Str(s) => write_string(s, out), JsonValue::Arr(items) => { out.push('['); for (i, item) in items.iter().enumerate() { if i > 0 { out.push(','); } write_value(item, out); } out.push(']'); } JsonValue::Obj(entries) => { out.push('{'); for (i, (key, val)) in entries.iter().enumerate() { if i > 0 { out.push(','); } write_string(key, out); out.push(':'); write_value(val, out); } out.push('}'); } } } /// 以 JSON 兼容形式渲染数字。整数打印时不带小数部分,符合常见预期 /// (例如 `3` 而非 `3.0`)。 /// Render a number in a JSON-compatible form. Integers print without a /// fractional part to match common expectations (e.g. `3` not `3.0`). fn write_number(n: f64, out: &mut String) { if n.is_finite() { // 整数走 i64 分支;浮点数走最短表示分支。 // Integers take the i64 branch; fractional numbers take the shortest-repr branch. if n.fract() == 0.0 && n.abs() < 1e16 { let _ = write!(out, "{}", n as i64); } else { // 通过 format! 得到 Ryu 风格的最短表示:可往返且无需引入依赖。 // Use Ryu-style shortest representation via format!: this gives // round-trippable floats without pulling in a dependency. let _ = write!(out, "{}", n); } } else { // JSON 无法表示无穷或 NaN;输出 null 以保持有效。 // JSON has no representation for infinity or NaN. Emit null to stay valid. out.push_str("null"); } } /// 将字符串转义并加上引号后写入 `out`。 /// Escape and quote a string into `out`. fn write_string(s: &str, out: &mut String) { out.push('"'); for c in s.chars() { match c { '"' => out.push_str("\\\""), '\\' => out.push_str("\\\\"), '\n' => out.push_str("\\n"), '\r' => out.push_str("\\r"), '\t' => out.push_str("\\t"), '\u{0008}' => out.push_str("\\b"), '\u{000C}' => out.push_str("\\f"), c if (c as u32) < 0x20 => { let _ = write!(out, "\\u{:04x}", c as u32); } c => out.push(c), } } out.push('"'); }