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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Rules for valid keys and dotted paths (spec § 4).
//!
//! Under spec 0.7:
//! - Each key segment is trimmed of leading/trailing ASCII whitespace
//! (the OUTER trim only), then validated **before** escape-decoding —
//! these functions look at the raw, still-escaped segment text, not
//! the decoded result. That ordering matters: § 3.7 defines thirteen
//! key-context escapes (`\\`, `\,`, `\}`, `\]`, `\{`, `\[`, `\n`,
//! `\r`, `\.`, `\:`, `\"`, `\'`, `` \` ``) plus `\uXXXX`, so a
//! decoded segment legitimately CAN contain a `,` / `{` / `}` / `[` /
//! `]` / LF / CR / quote byte when it arrived via its escape.
//! Checking the raw text instead lets those through while still
//! rejecting the same byte when it appears bare (unescaped) in the
//! source — which is what actually needs to be forbidden, e.g. so a
//! raw `,` inside an inline compound can't be mistaken for anything
//! but the compound's own pair/item separator.
//! - A segment is either a `<bare-segment>` or a `<quoted-segment>`
//! (§ 5.3.1 / § 5.3.3), identified POSITIONALLY: a segment whose
//! first byte is `"`, `'`, or `` ` `` is quoted; quotes elsewhere
//! are ordinary key chars. The two forms are validated against
//! different character classes (see [`check_key`]).
//! - Internal whitespace (space / tab) is allowed inside segments.
//! - `#` is allowed (single `#` has no special meaning in 0.7).
//! - Forbidden RAW (unescaped) bytes in a bare segment: `,`, `{`, `}`,
//! `[`, `]`, `(`, `)`, raw control bytes, and DEL (spec 0.7 § 4
//! `<key-char>`). The control-byte rule subsumes the LF/CR arms.
//! `:` and `.` stay unlisted: callers slice keys at the first
//! unescaped `:` and split at unescaped `.` before validation, so
//! raw ones cannot reach here — same reason as in 0.6.0. `(` / `)`
//! have no § 3.7 escape at all, so they are forbidden even when the
//! caller tries to escape them (`decode_key_segment` rejects
//! `\(` / `\)` as an unrecognised escape before this distinction
//! would matter). A byte immediately following an unescaped `\` is
//! always skipped here — validating that it is one of the fourteen
//! recognised escapes is `decode_key_segment`'s job, not this
//! function's.
//! - Empty (or empty-after-trim, by the caller) → `EmptyKey`.
/// Raw control byte / DEL forbidden by spec 0.7 § 4 `<key-char>` /
/// `<dq-char>` / `<sq-char>` / `<bt-char>`: any byte < 0x20 except tab
/// (0x09), VT (0x0B), and FF (0x0C), plus DEL (0x7F). (This subsumes
/// the 0.6.0-era explicit LF/CR arms.)
pub
/// Outcome of validating one raw (already-outer-trimmed) key segment.
pub
/// Validate one raw, already-outer-trimmed key segment (spec 0.7
/// § 5.3.1). A segment whose first byte is `"`, `'`, or `` ` `` is a
/// `<quoted-segment>` (§ 5.3.3's positional rule) and is validated
/// against `<dq-char>`/`<sq-char>`/`<bt-char>`; anything else is a
/// `<bare-segment>` validated against `<key-char>`.
pub