1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! JSON string encoding, shared by every artifact this workspace writes.
//! 本工作区写出的每个 JSON 工件共用的 JSON 字符串编码。
//!
//! Three artifacts need it, and they used to disagree: the build-diagnostics
//! document, the MIR JSONL artifact, and the generated editor-snippet file. Two
//! of the three carried a private "replace `\` and `"`" copy, which is not JSON
//! encoding at all — RFC 8259 also requires every code point below U+0020 to be
//! escaped — so those two could emit a raw tab or newline inside a string.
//! 有三份工件需要它,而它们此前并不一致:构建诊断文档、MIR JSONL 工件、以及生成的编辑器
//! 片段文件。其中两份各带一份私有的“只替换 `\` 与 `"`”副本,那根本不是 JSON 编码——
//! RFC 8259 还要求转义所有低于 U+0020 的码点——因此那两份会在字符串里原样写出制表符或换行。
use Write as _;
/// Append `value` to `output` as one quoted JSON string literal.
/// 把 `value` 作为一个带引号的 JSON 字符串字面量追加到 `output`。
///
/// # Why the obvious implementation is wrong
/// 为什么直白写法是错的
///
/// `value.replace('\\', "\\\\").replace('"', "\\\"")` is the shape a reader
/// reaches for first, and it is wrong in a way this workspace's own tests cannot
/// see: a tab or a newline inside a name is emitted raw, which makes the record
/// invalid for every conforming reader, while the lenient parser in this crate
/// still accepts it. A round-trip test therefore passes on invalid output. That
/// is exactly what happened to `MirGraph::to_jsonl`, and it is why the pinning
/// test below asserts the absence of raw control characters rather than a round
/// trip.
/// `value.replace('\\', "\\\\").replace('"', "\\\"")` 是读者最先想到的写法,而它的错处
/// 恰是本工作区自己的测试看不见的:名字里的制表符或换行会被原样写出,使记录对任何合规读取器
/// 非法,而本 crate 的宽松解析器仍然接受它。于是往返测试会在非法输出上通过——`MirGraph::to_jsonl`
/// 正是如此,这也是下面的钉子测试断言“不存在原样控制字符”而不是做往返的原因。
///
/// # Boundary
/// 边界
///
/// The escape set is exactly RFC 8259's: the quotation mark, the reverse
/// solidus, and U+0000–U+001F (the short form where JSON defines one, `\u00XX`
/// otherwise, so even a NUL is representable). Nothing else is escaped, so
/// non-ASCII text stays readable in the artifact.
/// 转义集恰好是 RFC 8259 的那一份:引号、反斜杠、以及 U+0000–U+001F(JSON 定义了短形式
/// 的用短形式,其余用 `\u00XX`,因此连 NUL 也能表示)。其余字符一律不转义,非 ASCII 文本
/// 因此在工件里保持可读。
/// Encode `value` as a complete JSON string, quotation marks included.
/// 把 `value` 编码为完整的 JSON 字符串,含两侧引号。