1use std::borrow::Cow;
14
15use serde_json::Value;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct PartialParse {
20 pub value: Option<Value>,
22 pub state: PartialParseState,
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28#[non_exhaustive]
29pub enum PartialParseState {
30 UndefinedInput,
32 SuccessfulParse,
34 RepairedParse,
36 FailedParse,
38}
39
40#[must_use]
51pub fn parse_optional(text: Option<&str>) -> PartialParse {
52 text.map_or(
53 PartialParse {
54 value: None,
55 state: PartialParseState::UndefinedInput,
56 },
57 parse_partial,
58 )
59}
60
61#[must_use]
63pub fn parse_partial(text: &str) -> PartialParse {
64 if let Ok(value) = crate::json::parse(text) {
65 return PartialParse {
66 value: Some(value),
67 state: PartialParseState::SuccessfulParse,
68 };
69 }
70 let repaired = repair(text);
71 match crate::json::parse(&repaired) {
72 Ok(value) => PartialParse {
73 value: Some(value),
74 state: PartialParseState::RepairedParse,
75 },
76 Err(_) => PartialParse {
77 value: None,
78 state: PartialParseState::FailedParse,
79 },
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
84enum State {
85 Root,
86 Finish,
87 InsideString,
88 InsideStringEscape,
89 InsideStringUnicodeEscape,
90 InsideLiteral,
91 InsideNumber,
92 InsideObjectStart,
93 InsideObjectKey,
94 InsideObjectKeyEscape,
95 InsideObjectAfterKey,
96 InsideObjectBeforeValue,
97 InsideObjectAfterValue,
98 InsideObjectAfterComma,
99 InsideArrayStart,
100 InsideArrayAfterValue,
101 InsideArrayAfterComma,
102}
103
104struct Repairer<'a> {
105 input: &'a str,
106 stack: Vec<State>,
107 last_valid_end: usize,
109 literal_start: usize,
110 unicode_escape_digits: u8,
111 unicode_escape_value: u16,
112 pending_high_surrogate: bool,
113}
114
115impl Repairer<'_> {
116 fn top(&self) -> State {
117 self.stack.last().copied().unwrap_or(State::Finish)
119 }
120
121 fn replace_top(&mut self, state: State) {
122 self.stack.pop();
123 self.stack.push(state);
124 }
125
126 fn process_value_start(&mut self, ch: char, start: usize, end: usize, swap: State) {
127 match ch {
128 '"' => {
129 self.last_valid_end = end;
130 self.replace_top(swap);
131 self.stack.push(State::InsideString);
132 }
133 'f' | 't' | 'n' => {
134 self.last_valid_end = end;
135 self.literal_start = start;
136 self.replace_top(swap);
137 self.stack.push(State::InsideLiteral);
138 }
139 '-' => {
140 self.replace_top(swap);
141 self.stack.push(State::InsideNumber);
142 }
143 '0'..='9' => {
144 self.last_valid_end = end;
145 self.replace_top(swap);
146 self.stack.push(State::InsideNumber);
147 }
148 '{' => {
149 self.last_valid_end = end;
150 self.replace_top(swap);
151 self.stack.push(State::InsideObjectStart);
152 }
153 '[' => {
154 self.last_valid_end = end;
155 self.replace_top(swap);
156 self.stack.push(State::InsideArrayStart);
157 }
158 _ => {}
159 }
160 }
161
162 fn process_after_object_value(&mut self, ch: char, end: usize) {
163 match ch {
164 ',' => self.replace_top(State::InsideObjectAfterComma),
165 '}' => {
166 self.last_valid_end = end;
167 self.stack.pop();
168 }
169 _ => {}
170 }
171 }
172
173 fn process_after_array_value(&mut self, ch: char, end: usize) {
174 match ch {
175 ',' => self.replace_top(State::InsideArrayAfterComma),
176 ']' => {
177 self.last_valid_end = end;
178 self.stack.pop();
179 }
180 _ => {}
181 }
182 }
183
184 fn step(&mut self, ch: char, start: usize, end: usize) {
185 match self.top() {
186 State::Root => self.process_value_start(ch, start, end, State::Finish),
187 State::Finish => {}
188 State::InsideObjectStart => match ch {
189 '"' => self.replace_top(State::InsideObjectKey),
190 '}' => {
191 self.last_valid_end = end;
192 self.stack.pop();
193 }
194 _ => {}
195 },
196 State::InsideObjectAfterComma => {
197 if ch == '"' {
198 self.replace_top(State::InsideObjectKey);
199 }
200 }
201 State::InsideObjectKey => match ch {
202 '"' => self.replace_top(State::InsideObjectAfterKey),
203 '\\' => self.stack.push(State::InsideObjectKeyEscape),
204 _ => {}
205 },
206 State::InsideObjectKeyEscape => {
207 self.stack.pop();
208 }
209 State::InsideObjectAfterKey => {
210 if ch == ':' {
211 self.replace_top(State::InsideObjectBeforeValue);
212 }
213 }
214 State::InsideObjectBeforeValue => {
215 self.process_value_start(ch, start, end, State::InsideObjectAfterValue);
216 }
217 State::InsideObjectAfterValue => self.process_after_object_value(ch, end),
218 State::InsideString => match ch {
219 '"' => {
220 self.stack.pop();
221 self.last_valid_end = end;
222 }
223 '\\' => self.stack.push(State::InsideStringEscape),
224 _ => self.last_valid_end = end,
225 },
226 State::InsideArrayStart => {
227 if ch == ']' {
228 self.last_valid_end = end;
229 self.stack.pop();
230 } else {
231 if ch != '-' {
234 self.last_valid_end = end;
235 }
236 self.process_value_start(ch, start, end, State::InsideArrayAfterValue);
237 }
238 }
239 State::InsideArrayAfterValue => match ch {
240 ',' => self.replace_top(State::InsideArrayAfterComma),
241 ']' => {
242 self.last_valid_end = end;
243 self.stack.pop();
244 }
245 _ => self.last_valid_end = end,
246 },
247 State::InsideArrayAfterComma => {
248 self.process_value_start(ch, start, end, State::InsideArrayAfterValue);
249 }
250 State::InsideStringEscape => {
251 self.stack.pop();
252 if ch == 'u' {
253 self.unicode_escape_digits = 0;
254 self.unicode_escape_value = 0;
255 self.stack.push(State::InsideStringUnicodeEscape);
256 } else {
257 self.last_valid_end = end;
258 }
259 }
260 State::InsideStringUnicodeEscape => {
261 if let Some(digit) = ch.to_digit(16) {
262 self.unicode_escape_value = (self.unicode_escape_value << 4) | digit as u16;
263 self.unicode_escape_digits += 1;
264 if self.unicode_escape_digits == 4 {
265 self.stack.pop();
266 if (0xD800..=0xDBFF).contains(&self.unicode_escape_value) {
267 self.pending_high_surrogate = true;
269 } else if !self.pending_high_surrogate
270 || (0xDC00..=0xDFFF).contains(&self.unicode_escape_value)
271 {
272 self.pending_high_surrogate = false;
273 self.last_valid_end = end;
274 }
275 }
276 }
277 }
278 State::InsideNumber => match ch {
279 '0'..='9' => self.last_valid_end = end,
280 'e' | 'E' | '-' | '+' | '.' => {}
281 ',' => {
282 self.stack.pop();
283 if self.top() == State::InsideArrayAfterValue {
284 self.process_after_array_value(ch, end);
285 }
286 if self.top() == State::InsideObjectAfterValue {
287 self.process_after_object_value(ch, end);
288 }
289 }
290 '}' => {
291 self.stack.pop();
292 if self.top() == State::InsideObjectAfterValue {
293 self.process_after_object_value(ch, end);
294 }
295 }
296 ']' => {
297 self.stack.pop();
298 if self.top() == State::InsideArrayAfterValue {
299 self.process_after_array_value(ch, end);
300 }
301 }
302 _ => {
303 self.stack.pop();
304 }
305 },
306 State::InsideLiteral => {
307 let partial = &self.input[self.literal_start..end];
308 if !"false".starts_with(partial)
309 && !"true".starts_with(partial)
310 && !"null".starts_with(partial)
311 {
312 self.stack.pop();
313 if self.top() == State::InsideObjectAfterValue {
314 self.process_after_object_value(ch, end);
315 } else if self.top() == State::InsideArrayAfterValue {
316 self.process_after_array_value(ch, end);
317 }
318 } else {
319 self.last_valid_end = end;
320 }
321 }
322 }
323 }
324
325 fn finish(self) -> String {
326 let mut result = String::with_capacity(self.last_valid_end + self.stack.len());
327 result.push_str(&self.input[..self.last_valid_end]);
328 for state in self.stack.iter().rev() {
329 match state {
330 State::InsideString => result.push('"'),
331 State::InsideObjectKey
332 | State::InsideObjectAfterKey
333 | State::InsideObjectAfterComma
334 | State::InsideObjectStart
335 | State::InsideObjectBeforeValue
336 | State::InsideObjectAfterValue => result.push('}'),
337 State::InsideArrayStart
338 | State::InsideArrayAfterComma
339 | State::InsideArrayAfterValue => result.push(']'),
340 State::InsideLiteral => {
341 let partial = &self.input[self.literal_start..];
342 for literal in ["true", "false", "null"] {
343 if let Some(rest) = literal.strip_prefix(partial) {
344 result.push_str(rest);
345 break;
346 }
347 }
348 }
349 State::Root
350 | State::Finish
351 | State::InsideStringEscape
352 | State::InsideObjectKeyEscape
353 | State::InsideStringUnicodeEscape
354 | State::InsideNumber => {}
355 }
356 }
357 result
358 }
359}
360
361#[must_use]
365pub fn repair(input: &str) -> Cow<'_, str> {
366 let mut repairer = Repairer {
367 input,
368 stack: vec![State::Root],
369 last_valid_end: 0,
370 literal_start: 0,
371 unicode_escape_digits: 0,
372 unicode_escape_value: 0,
373 pending_high_surrogate: false,
374 };
375 for (start, ch) in input.char_indices() {
376 let end = start + ch.len_utf8();
377 repairer.step(ch, start, end);
378 }
379 let result = repairer.finish();
380 if result == input {
381 Cow::Borrowed(input)
382 } else {
383 Cow::Owned(result)
384 }
385}