Skip to main content

atmos/os_lib/js/builtins/
console_math_json.rs

1// 分割: builtins.rs より機械的に移動(2026-07-16 リファクタ フェーズ2)。
2// ロジック不変。可視性のみ pub(crate) へ昇格し、親が pub(crate) use で再エクスポート。
3use super::*;
4
5// ============ console ============
6
7pub(crate) fn console_log(it: &mut Interp, _this: Value, args: &[Value]) -> Result<Value, Value> {
8    let parts: Vec<String> = args.iter().map(display_value).collect();
9    let line = parts.join(" ");
10    if !crate::kernel::uart::is_silent() {
11        crate::println!("{}", line);
12    }
13    it.out.push_str(&line);
14    it.out.push('\n');
15    Ok(Value::Undefined)
16}
17
18/// console 表示用(文字列はクォート無し、オブジェクトは簡易 JSON 風)。
19/// `structuredClone`/`JSON.stringify` にあったのと同じ「循環参照で無限再帰」バグが
20/// ここにもあった。`console.log(a)`(`a.self = a`)は特に日常的にありうる操作のため、
21/// この no_std 環境でのクラッシュ/ハングとしては最も踏みやすいケースだった。祖先追跡を
22/// 追加し、循環を検出したら(ブラウザ devtools と同じ慣習で)`[Circular]` と表示する。
23pub(crate) fn display_value(v: &Value) -> String {
24    display_value_inner(v, &mut Vec::new())
25}
26pub(crate) fn display_value_inner(v: &Value, ancestors: &mut Vec<super::super::value::ObjRef>) -> String {
27    match v {
28        Value::Str(s) => (**s).clone(),
29        Value::Object(o) => {
30            // `console.log(new Proxy([1,2,3], {}))` が `Array`/`Plain` 以外への
31            // 素通しフォールバック(`to_js_string()`)に落ち、`[ 1, 2, 3 ]` の
32            // ような角括弧付き表示ではなく素の `"1,2,3"` になっていた(`Proxy`
33            // 越しでもコンソール表示は target と同じ見た目になるべき)。他の
34            // ObjKind と同じ「実体が別の場所にある」系の透過性修正で、target を
35            // 解決してから同じ表示ロジックへ再帰する。
36            if let ObjKind::Proxy { target, .. } = &o.borrow().kind {
37                let target = unwrap_proxy_target(target);
38                if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
39                    return String::from("[Circular]");
40                }
41                ancestors.push(o.clone());
42                let out = display_value_inner(&Value::Object(target), ancestors);
43                ancestors.pop();
44                return out;
45            }
46            let kind_tag = matches!(&o.borrow().kind, ObjKind::Array(_) | ObjKind::Plain);
47            if !kind_tag {
48                return v.to_js_string();
49            }
50            if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
51                return String::from("[Circular]");
52            }
53            ancestors.push(o.clone());
54            let b = o.borrow();
55            let out = match &b.kind {
56                ObjKind::Array(items) => {
57                    let parts: Vec<String> =
58                        items.iter().map(|x| display_inner_with(x, ancestors)).collect();
59                    format!("[ {} ]", parts.join(", "))
60                }
61                ObjKind::Plain => {
62                    let parts: Vec<String> = b
63                        .props
64                        .iter()
65                        .map(|(k, val)| format!("{}: {}", k, display_inner_with(val, ancestors)))
66                        .collect();
67                    format!("{{ {} }}", parts.join(", "))
68                }
69                _ => v.to_js_string(),
70            };
71            drop(b);
72            ancestors.pop();
73            out
74        }
75        _ => v.to_js_string(),
76    }
77}
78pub(crate) fn display_inner_with(v: &Value, ancestors: &mut Vec<super::super::value::ObjRef>) -> String {
79    match v {
80        Value::Str(s) => format!("'{}'", s),
81        _ => display_value_inner(v, ancestors),
82    }
83}
84
85// ============ Math ============
86
87pub(crate) fn math_floor(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
88    Ok(Value::Number(libm::floor(arg(a, 0).to_number())))
89}
90pub(crate) fn math_ceil(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
91    Ok(Value::Number(libm::ceil(arg(a, 0).to_number())))
92}
93pub(crate) fn math_round(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
94    // JS の round は .5 を正方向へ。
95    let n = arg(a, 0).to_number();
96    Ok(Value::Number(libm::floor(n + 0.5)))
97}
98pub(crate) fn math_trunc(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
99    Ok(Value::Number(libm::trunc(arg(a, 0).to_number())))
100}
101pub(crate) fn math_abs(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
102    Ok(Value::Number(libm::fabs(arg(a, 0).to_number())))
103}
104pub(crate) fn math_sign(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
105    let n = arg(a, 0).to_number();
106    Ok(Value::Number(if n > 0.0 {
107        1.0
108    } else if n < 0.0 {
109        -1.0
110    } else {
111        n
112    }))
113}
114pub(crate) fn math_sqrt(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
115    Ok(Value::Number(libm::sqrt(arg(a, 0).to_number())))
116}
117pub(crate) fn math_pow(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
118    Ok(Value::Number(libm::pow(
119        arg(a, 0).to_number(),
120        arg(a, 1).to_number(),
121    )))
122}
123pub(crate) fn math_sin(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
124    Ok(Value::Number(libm::sin(arg(a, 0).to_number())))
125}
126pub(crate) fn math_cos(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
127    Ok(Value::Number(libm::cos(arg(a, 0).to_number())))
128}
129pub(crate) fn math_log(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
130    Ok(Value::Number(libm::log(arg(a, 0).to_number())))
131}
132pub(crate) fn math_exp(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
133    Ok(Value::Number(libm::exp(arg(a, 0).to_number())))
134}
135pub(crate) fn math_min(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
136    let mut m = f64::INFINITY;
137    for v in a {
138        let n = v.to_number();
139        if n.is_nan() {
140            return Ok(Value::Number(f64::NAN));
141        }
142        if n < m {
143            m = n;
144        }
145    }
146    Ok(Value::Number(m))
147}
148pub(crate) fn math_max(_: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
149    let mut m = f64::NEG_INFINITY;
150    for v in a {
151        let n = v.to_number();
152        if n.is_nan() {
153            return Ok(Value::Number(f64::NAN));
154        }
155        if n > m {
156            m = n;
157        }
158    }
159    Ok(Value::Number(m))
160}
161
162pub(crate) static RNG_SEED: AtomicU64 = AtomicU64::new(0x2545F4914F6CDD1D);
163pub(crate) fn math_random(_: &mut Interp, _t: Value, _a: &[Value]) -> Result<Value, Value> {
164    // xorshift64* で 0..1 の疑似乱数。
165    let mut x = RNG_SEED.load(Ordering::Relaxed);
166    x ^= x >> 12;
167    x ^= x << 25;
168    x ^= x >> 27;
169    RNG_SEED.store(x, Ordering::Relaxed);
170    let r = (x.wrapping_mul(0x2545F4914F6CDD1D) >> 11) as f64 / (1u64 << 53) as f64;
171    Ok(Value::Number(r))
172}
173
174// ============ JSON ============
175
176/// `JSON.parse(text, reviver)`。以前は `reviver`(各キーをボトムアップで巡り値を
177/// 差し替える/`undefined` を返せば削除する変換関数)を完全に無視していた。
178pub(crate) fn json_parse(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
179    let s = arg(a, 0).to_js_string();
180    let root = match crate::os_lib::json::parse(&s) {
181        Ok(jv) => json_to_value(&jv),
182        Err(e) => return Err(it.error(format!("JSON.parse: {}", e))),
183    };
184    let reviver = arg(a, 1);
185    if !matches!(&reviver, Value::Object(o) if o.borrow().is_callable()) {
186        return Ok(root);
187    }
188    // 仕様の InternalizeJSONProperty: ルート値を `{"": root}` という一時ホルダーに包み、
189    // そのキー "" から再帰的に internalize することで、ルート自身にも reviver が
190    // 一様に適用されるようにする。
191    let holder = Obj::plain();
192    holder.borrow_mut().props.insert(String::new(), root);
193    internalize_json_property(it, &Value::Object(holder), "", &reviver)
194}
195pub(crate) fn internalize_json_property(
196    it: &mut Interp,
197    holder: &Value,
198    key: &str,
199    reviver: &Value,
200) -> Result<Value, Value> {
201    let val = it.get_property(holder, key)?;
202    let val = if let Value::Object(o) = &val {
203        let is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
204        if is_array {
205            let len = match &o.borrow().kind {
206                ObjKind::Array(items) => items.len(),
207                _ => 0,
208            };
209            for i in 0..len {
210                let new_elem =
211                    internalize_json_property(it, &val, &i.to_string(), reviver)?;
212                if let ObjKind::Array(items) = &mut o.borrow_mut().kind {
213                    if i < items.len() {
214                        items[i] = new_elem;
215                    }
216                }
217            }
218        } else {
219            let keys: Vec<String> = o.borrow().props.keys().map(Clone::clone).collect();
220            for k in keys {
221                let new_val = internalize_json_property(it, &val, &k, reviver)?;
222                if matches!(new_val, Value::Undefined) {
223                    o.borrow_mut().props.shift_remove(&k);
224                } else {
225                    o.borrow_mut().props.insert(k, new_val);
226                }
227            }
228        }
229        val
230    } else {
231        val
232    };
233    it.call_value(reviver, holder.clone(), &[Value::str(key), val])
234}
235/// `JSON.stringify(value, replacer, space)`。以前は `space`(インデント整形)と
236/// `replacer`(キーのフィルタ用配列、または値を差し替える関数)の両方を完全に無視していた。
237pub(crate) fn json_stringify(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
238    let v = arg(a, 0);
239    let replacer = arg(a, 1);
240    let key_filter: Option<Vec<String>> = match &replacer {
241        Value::Object(o) if matches!(&o.borrow().kind, ObjKind::Array(_)) => {
242            Some(this_items(&replacer).iter().map(|x| x.to_js_string()).collect())
243        }
244        _ => None,
245    };
246    let replacer_fn = match &replacer {
247        Value::Object(o) if o.borrow().is_callable() => Some(replacer.clone()),
248        _ => None,
249    };
250    let indent = match arg(a, 2) {
251        Value::Number(n) => {
252            let n = (n as usize).min(10);
253            " ".repeat(n)
254        }
255        Value::Str(s) => s.chars().take(10).collect(),
256        _ => String::new(),
257    };
258    // 仕様上 `replacer` 関数はルート値自身にも `("", value)` として一度呼ばれる。
259    let v = if let Some(rf) = &replacer_fn {
260        it.call_value(rf, v.clone(), &[Value::str(""), v.clone()])?
261    } else {
262        v
263    };
264    match value_to_json_string(
265        it,
266        &v,
267        &indent,
268        0,
269        key_filter.as_ref(),
270        replacer_fn.as_ref(),
271    )? {
272        Some(s) => Ok(Value::str(s)),
273        None => Ok(Value::Undefined),
274    }
275}
276
277/// `JSON.rawJSON(text)`(ES2025)が丸ごと未対応だった。数値精度を保ったまま
278/// (例: `Number`の安全整数範囲を超える巨大な整数)JSON文字列へ埋め込むための
279/// マーカーオブジェクトを作る。内部スロットが無い簡略実装のため、`frozen`+
280/// `proto: None`+`rawJSON`という1個の own プロパティのみを持つ、という形状
281/// そのものを「rawJSONオブジェクトである」印として扱う(`JSON.isRawJSON`も
282/// 同じ形状チェックで判定する)。2026-07-18 発見・実装。
283pub(crate) fn json_raw_json(it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
284    let s = arg(a, 0).to_js_string();
285    let is_ws = |c: char| matches!(c, '\u{9}' | '\u{a}' | '\u{d}' | '\u{20}');
286    if s.is_empty() || s.chars().next().is_some_and(is_ws) || s.chars().last().is_some_and(is_ws) {
287        return Err(it.error("JSON.rawJSON: argument must not be empty or have leading/trailing whitespace"));
288    }
289    if let Err(e) = crate::os_lib::json::parse(&s) {
290        return Err(it.error(format!("JSON.rawJSON: {}", e)));
291    }
292    let obj = Obj::plain();
293    {
294        let mut b = obj.borrow_mut();
295        b.props.insert("rawJSON".into(), Value::str(s));
296        b.frozen = true;
297        b.sealed = true;
298        b.non_extensible = true;
299    }
300    Ok(Value::Object(obj))
301}
302/// `JSON.isRawJSON(value)`(ES2025)。`json_raw_json`が作る形状
303/// (`frozen`かつ`proto: None`かつ own プロパティが`rawJSON`(文字列)1個のみ)
304/// と一致するかで判定する簡略実装。
305pub(crate) fn json_is_raw_json(_it: &mut Interp, _t: Value, a: &[Value]) -> Result<Value, Value> {
306    let is_raw = match arg(a, 0) {
307        Value::Object(o) => {
308            let b = o.borrow();
309            b.frozen
310                && b.proto.is_none()
311                && b.props.len() == 1
312                && matches!(b.props.get("rawJSON"), Some(Value::Str(_)))
313        }
314        _ => false,
315    };
316    Ok(Value::Bool(is_raw))
317}
318pub(crate) fn json_to_value(jv: &crate::os_lib::json::JsonValue) -> Value {
319    use crate::os_lib::json::JsonValue as J;
320    match jv {
321        J::Null => Value::Null,
322        J::Bool(b) => Value::Bool(*b),
323        J::Number(n) => Value::Number(*n),
324        J::String(s) => Value::str(s.clone()),
325        J::Array(items) => Value::Object(Obj::array(items.iter().map(json_to_value).collect())),
326        J::Object(map) => {
327            let o = Obj::plain();
328            for (k, v) in map {
329                o.borrow_mut().props.insert(k.clone(), json_to_value(v));
330            }
331            Value::Object(o)
332        }
333    }
334}
335
336/// Value を JSON 文字列へ(undefined/関数は省略)。`indent` が空でなければ `depth` 段の
337/// インデント付き整形出力にする(`JSON.stringify(v, null, 2)` 等)。`key_filter` が
338/// `Some` なら(`replacer` が配列指定のとき)オブジェクトのキーをそれで絞り込む
339/// (配列要素自体には適用しない。仕様どおり)。`replacer_fn` が `Some` なら各値を
340/// `replacer_fn(key, value)`(`this` はプロパティの持ち主)で差し替えてから直列化する。
341pub(crate) fn value_to_json_string(
342    it: &mut Interp,
343    v: &Value,
344    indent: &str,
345    depth: usize,
346    key_filter: Option<&Vec<String>>,
347    replacer_fn: Option<&Value>,
348) -> Result<Option<String>, Value> {
349    value_to_json_string_inner(it, v, indent, depth, key_filter, replacer_fn, &mut Vec::new())
350}
351/// `ancestors` は現在の再帰パス上にある(まだ直列化を終えていない)オブジェクトの一覧
352/// (循環参照検出用のスタック。同一オブジェクトへの「兄弟」参照は問題ない — 構造共有として
353/// 正しく複数回直列化される — が、自分自身が祖先に含まれていれば真の循環参照)。
354/// 以前はこの追跡が無く、循環参照を渡すと無限再帰に陥っていた(`structuredClone` に
355/// あった既知のバグと同種。この no_std 環境ではクラッシュ/ハングになり得る)。仕様どおり
356/// `TypeError`(`"Converting circular structure to JSON"`)を投げるようにした。
357pub(crate) fn value_to_json_string_inner(
358    it: &mut Interp,
359    v: &Value,
360    indent: &str,
361    depth: usize,
362    key_filter: Option<&Vec<String>>,
363    replacer_fn: Option<&Value>,
364    ancestors: &mut Vec<super::super::value::ObjRef>,
365) -> Result<Option<String>, Value> {
366    if depth > 30 || ancestors.len() > 30 {
367        return Err(it.type_error("Maximum JSON nesting depth exceeded"));
368    }
369    let pretty = !indent.is_empty();
370    let nl_cur = if pretty {
371        format!("\n{}", indent.repeat(depth))
372    } else {
373        String::new()
374    };
375    let nl_inner = if pretty {
376        format!("\n{}", indent.repeat(depth + 1))
377    } else {
378        String::new()
379    };
380    let colon = if pretty { ": " } else { ":" };
381    Ok(match v {
382        Value::Undefined => None,
383        Value::Null => Some("null".into()),
384        Value::Bool(b) => Some(if *b { "true".into() } else { "false".into() }),
385        Value::Number(n) => Some(if n.is_finite() {
386            fmt_number(*n)
387        } else {
388            "null".into()
389        }),
390        Value::Str(s) => Some(json_quote(s)),
391        // `JSON.stringify` は仕様上 `BigInt` を直列化不能として無条件に `TypeError` を
392        // 投げるべきだが、以前は静かに省略していた(`undefined`/関数と同じ「キーごと
393        // 消える」扱いになっており、`BigInt` を含むオブジェクトが気づかれずに不完全な
394        // JSON を生成するバグだった)。
395        Value::BigInt(_) => return Err(it.error("Do not know how to serialize a BigInt")),
396        Value::Object(o) => {
397            // `JSON.rawJSON(...)`が返すマーカーオブジェクトは、通常のオブジェクトと
398            // して`{"rawJSON":"..."}`にシリアライズするのではなく、保持している
399            // JSON文字列をそのまま(引用符無しで)埋め込む必要がある
400            // (巨大整数等をNumberの精度損失無しで直列化するための機能のため)。
401            let raw_json = {
402                let b = o.borrow();
403                if b.frozen
404                    && b.proto.is_none()
405                    && b.props.len() == 1
406                    && matches!(b.props.get("rawJSON"), Some(Value::Str(_)))
407                {
408                    match b.props.get("rawJSON") {
409                        Some(Value::Str(s)) => Some(s.to_string()),
410                        _ => None,
411                    }
412                } else {
413                    None
414                }
415            };
416            if let Some(s) = raw_json {
417                return Ok(Some(s));
418            }
419            let is_date = matches!(&o.borrow().kind, ObjKind::DateObj(_));
420            if is_date {
421                let ms = match &o.borrow().kind {
422                    ObjKind::DateObj(ms) => *ms,
423                    _ => unreachable!(),
424                };
425                return Ok(Some(json_quote(&format_iso(ms))));
426            }
427            let is_fn = matches!(&o.borrow().kind, ObjKind::Function(_) | ObjKind::Native { .. });
428            if is_fn {
429                return Ok(None);
430            }
431            // `Proxy` も同じ Proxy 透過漏れの一種(自身は `props` を持たないため、素通しすると
432            // 常に `{}` になっていた)。target フォワードのみの Proxy を想定した簡略対応
433            // (`get`/`ownKeys` トラップ経由の値は反映されない)。
434            let proxy_target = match &o.borrow().kind {
435                ObjKind::Proxy { target, .. } => Some(target.clone()),
436                _ => None,
437            };
438            if let Some(target) = proxy_target {
439                return value_to_json_string_inner(
440                    it,
441                    &Value::Object(unwrap_proxy_target(&target)),
442                    indent,
443                    depth,
444                    key_filter,
445                    replacer_fn,
446                    ancestors,
447                );
448            }
449            // `toJSON()`(Date だけの特別扱いではなく、任意のオブジェクトに定義できる
450            // カスタムシリアライズ用の定番フック。ES5 の `Date.prototype.toJSON` 以来
451            // 広く使われる)が丸ごと未対応で、Date 以外のオブジェクトでは呼出し可能な
452            // `toJSON` が定義されていても常に無視されていた。仕様どおり、この置換は
453            // 循環参照検出より前に行う。
454            let to_json = it.get_property(v, "toJSON").unwrap_or(Value::Undefined);
455            if matches!(&to_json, Value::Object(f) if f.borrow().is_callable()) {
456                let replaced = it.call_value(&to_json, v.clone(), &[])?;
457                return value_to_json_string_inner(
458                    it, &replaced, indent, depth, key_filter, replacer_fn, ancestors,
459                );
460            }
461            // 循環参照検出: 自分自身が既に「直列化中の祖先」に含まれていれば TypeError。
462            if ancestors.iter().any(|a| Rc::ptr_eq(a, o)) {
463                return Err(it.error("Converting circular structure to JSON"));
464            }
465            ancestors.push(o.clone());
466            let result = (|| -> Result<Option<String>, Value> {
467                let kind_is_array = matches!(&o.borrow().kind, ObjKind::Array(_));
468                if kind_is_array {
469                    let items = match &o.borrow().kind {
470                        ObjKind::Array(items) => items.clone(),
471                        _ => unreachable!(),
472                    };
473                    if items.is_empty() {
474                        return Ok(Some("[]".into()));
475                    }
476                    let mut parts = Vec::with_capacity(items.len());
477                    for (i, x) in items.iter().enumerate() {
478                        let x = if let Some(rf) = replacer_fn {
479                            it.call_value(rf, v.clone(), &[Value::str(i.to_string()), x.clone()])?
480                        } else {
481                            x.clone()
482                        };
483                        let s = value_to_json_string_inner(
484                            it,
485                            &x,
486                            indent,
487                            depth + 1,
488                            key_filter,
489                            replacer_fn,
490                            ancestors,
491                        )?
492                        .unwrap_or_else(|| "null".into());
493                        parts.push(s);
494                    }
495                    return Ok(Some(format!(
496                        "[{}{}{}]",
497                        nl_inner,
498                        parts.join(&format!(",{}", nl_inner)),
499                        nl_cur
500                    )));
501                }
502                if is_internal_host(&o.borrow().kind) {
503                    return Ok(Some("{}".into()));
504                }
505                // accessors(getter/setter 限定プロパティ)専用マップも見ておらず
506                // `JSON.stringify({get x(){return 1;}})` が `"{}"` になるバグだった
507                // (`in`/`for...in`/`Object.keys` 等と同種)。
508                let plain_keys: Vec<(String, ())> = o
509                    .borrow()
510                    .props
511                    .keys()
512                    .filter(|k| !is_symbol_like_key(k))
513                    .filter(|k| o.borrow().attrs.get(*k).copied().unwrap_or_default().enumerable)
514                    .map(|k| (k.clone(), ()))
515                    .collect();
516                let mut keys: Vec<String> = super::object_array::spec_key_order(plain_keys)
517                    .into_iter()
518                    .map(|(k, _)| k)
519                    .collect();
520                for k in accessor_only_keys(&o.borrow()) {
521                    if o.borrow().attrs.get(&k).copied().unwrap_or_default().enumerable {
522                        keys.push(k);
523                    }
524                }
525                let mut parts = Vec::new();
526                for k in keys {
527                    if let Some(filter) = key_filter {
528                        if !filter.contains(&k) {
529                            continue;
530                        }
531                    }
532                    let getter = o.borrow().accessors.get(&k).and_then(|acc| acc.get.clone());
533                    let val = if let Some(g) = getter {
534                        it.call_value(&g, Value::Object(o.clone()), &[])?
535                    } else {
536                        o.borrow().props.get(&k).cloned().unwrap_or(Value::Undefined)
537                    };
538                    let val = if let Some(rf) = replacer_fn {
539                        it.call_value(rf, v.clone(), &[Value::str(k.clone()), val])?
540                    } else {
541                        val
542                    };
543                    if let Some(s) = value_to_json_string_inner(
544                        it,
545                        &val,
546                        indent,
547                        depth + 1,
548                        key_filter,
549                        replacer_fn,
550                        ancestors,
551                    )? {
552                        parts.push(format!("{}{}{}", json_quote(&k), colon, s));
553                    }
554                }
555                if parts.is_empty() {
556                    return Ok(Some("{}".into()));
557                }
558                Ok(Some(format!(
559                    "{{{}{}{}}}",
560                    nl_inner,
561                    parts.join(&format!(",{}", nl_inner)),
562                    nl_cur
563                )))
564            })();
565            ancestors.pop();
566            return result;
567        }
568    })
569}
570pub(crate) fn json_quote(s: &str) -> String {
571    let mut out = String::from("\"");
572    for c in s.chars() {
573        match c {
574            '"' => out.push_str("\\\""),
575            '\\' => out.push_str("\\\\"),
576            '\n' => out.push_str("\\n"),
577            '\t' => out.push_str("\\t"),
578            '\r' => out.push_str("\\r"),
579            _ => out.push(c),
580        }
581    }
582    out.push('"');
583    out
584}
585