• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

facet-rs / facet / 20165231858

12 Dec 2025 11:23AM UTC coverage: 57.831% (+0.2%) from 57.586%
20165231858

Pull #1255

github

web-flow
Merge d988a5ef7 into a8626bccf
Pull Request #1255: Introduce facet-format

968 of 1685 new or added lines in 18 files covered. (57.45%)

4 existing lines in 2 files now uncovered.

31400 of 54296 relevant lines covered (57.83%)

5827.68 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

37.25
/facet-format-json/src/parser.rs
1
extern crate alloc;
2

3
use alloc::{borrow::Cow, vec::Vec};
4

5
use facet_format::{
6
    FieldEvidence, FieldLocationHint, FormatParser, ParseEvent, ProbeStream, ScalarValue,
7
};
8
pub use facet_json::JsonError;
9
use facet_json::{AdapterToken, JsonErrorKind, SliceAdapter, SpannedAdapterToken};
10

11
/// Streaming JSON parser backed by `facet-json`'s `SliceAdapter`.
12
pub struct JsonParser<'de> {
13
    input: &'de [u8],
14
    adapter: SliceAdapter<'de, true>,
15
    stack: Vec<ContextState>,
16
    /// Cached event for `peek_event`.
17
    event_peek: Option<ParseEvent<'de>>,
18
    /// Whether the root value has started.
19
    root_started: bool,
20
    /// Whether the root value has fully completed.
21
    root_complete: bool,
22
    /// Absolute offset (in bytes) of the next unread token.
23
    current_offset: usize,
24
}
25

26
#[derive(Debug)]
27
enum ContextState {
28
    Object(ObjectState),
29
    Array(ArrayState),
30
}
31

32
#[derive(Debug)]
33
enum ObjectState {
34
    KeyOrEnd,
35
    Value,
36
    CommaOrEnd,
37
}
38

39
#[derive(Debug)]
40
enum ArrayState {
41
    ValueOrEnd,
42
    CommaOrEnd,
43
}
44

45
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46
enum DelimKind {
47
    Object,
48
    Array,
49
}
50

51
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
52
enum NextAction {
53
    ObjectKey,
54
    ObjectValue,
55
    ObjectComma,
56
    ArrayValue,
57
    ArrayComma,
58
    RootValue,
59
    RootFinished,
60
}
61

62
impl<'de> JsonParser<'de> {
63
    pub fn new(input: &'de [u8]) -> Self {
10✔
64
        Self {
10✔
65
            input,
10✔
66
            adapter: SliceAdapter::new(input),
10✔
67
            stack: Vec::new(),
10✔
68
            event_peek: None,
10✔
69
            root_started: false,
10✔
70
            root_complete: false,
10✔
71
            current_offset: 0,
10✔
72
        }
10✔
73
    }
10✔
74

75
    fn consume_token(&mut self) -> Result<SpannedAdapterToken<'de>, JsonError> {
118✔
76
        let token = self.adapter.next_token().map_err(JsonError::from)?;
118✔
77
        self.current_offset = token.span.offset + token.span.len;
118✔
78
        Ok(token)
118✔
79
    }
118✔
80

81
    fn expect_colon(&mut self) -> Result<(), JsonError> {
18✔
82
        let token = self.consume_token()?;
18✔
83
        if !matches!(token.token, AdapterToken::Colon) {
18✔
NEW
84
            return Err(self.unexpected(&token, "':'"));
×
85
        }
18✔
86
        Ok(())
18✔
87
    }
18✔
88

89
    fn parse_value_start_with_token(
46✔
90
        &mut self,
46✔
91
        first: Option<SpannedAdapterToken<'de>>,
46✔
92
    ) -> Result<ParseEvent<'de>, JsonError> {
46✔
93
        let token = match first {
46✔
94
            Some(tok) => tok,
18✔
95
            None => self.consume_token()?,
28✔
96
        };
97

98
        self.root_started = true;
46✔
99

100
        match token.token {
46✔
101
            AdapterToken::ObjectStart => {
102
                self.stack.push(ContextState::Object(ObjectState::KeyOrEnd));
10✔
103
                Ok(ParseEvent::StructStart)
10✔
104
            }
105
            AdapterToken::ArrayStart => {
106
                self.stack.push(ContextState::Array(ArrayState::ValueOrEnd));
6✔
107
                Ok(ParseEvent::SequenceStart)
6✔
108
            }
109
            AdapterToken::String(s) => {
10✔
110
                let event = ParseEvent::Scalar(ScalarValue::Str(s));
10✔
111
                self.finish_value_in_parent();
10✔
112
                Ok(event)
10✔
113
            }
114
            AdapterToken::True => {
115
                self.finish_value_in_parent();
4✔
116
                Ok(ParseEvent::Scalar(ScalarValue::Bool(true)))
4✔
117
            }
118
            AdapterToken::False => {
NEW
119
                self.finish_value_in_parent();
×
NEW
120
                Ok(ParseEvent::Scalar(ScalarValue::Bool(false)))
×
121
            }
122
            AdapterToken::Null => {
123
                self.finish_value_in_parent();
2✔
124
                Ok(ParseEvent::Scalar(ScalarValue::Null))
2✔
125
            }
126
            AdapterToken::U64(n) => {
10✔
127
                self.finish_value_in_parent();
10✔
128
                Ok(ParseEvent::Scalar(ScalarValue::U64(n)))
10✔
129
            }
130
            AdapterToken::I64(n) => {
2✔
131
                self.finish_value_in_parent();
2✔
132
                Ok(ParseEvent::Scalar(ScalarValue::I64(n)))
2✔
133
            }
NEW
134
            AdapterToken::U128(n) => {
×
NEW
135
                self.finish_value_in_parent();
×
NEW
136
                Ok(ParseEvent::Scalar(ScalarValue::Str(Cow::Owned(
×
NEW
137
                    n.to_string(),
×
NEW
138
                ))))
×
139
            }
NEW
140
            AdapterToken::I128(n) => {
×
NEW
141
                self.finish_value_in_parent();
×
NEW
142
                Ok(ParseEvent::Scalar(ScalarValue::Str(Cow::Owned(
×
NEW
143
                    n.to_string(),
×
NEW
144
                ))))
×
145
            }
146
            AdapterToken::F64(n) => {
2✔
147
                self.finish_value_in_parent();
2✔
148
                Ok(ParseEvent::Scalar(ScalarValue::F64(n)))
2✔
149
            }
150
            AdapterToken::ObjectEnd | AdapterToken::ArrayEnd => {
NEW
151
                Err(self.unexpected(&token, "value"))
×
152
            }
NEW
153
            AdapterToken::Comma | AdapterToken::Colon => Err(self.unexpected(&token, "value")),
×
NEW
154
            AdapterToken::Eof => Err(JsonError::new(
×
NEW
155
                JsonErrorKind::UnexpectedEof { expected: "value" },
×
NEW
156
                token.span,
×
NEW
157
            )),
×
158
        }
159
    }
46✔
160

161
    fn finish_value_in_parent(&mut self) {
46✔
162
        if let Some(context) = self.stack.last_mut() {
46✔
163
            match context {
36✔
164
                ContextState::Object(state) => *state = ObjectState::CommaOrEnd,
18✔
165
                ContextState::Array(state) => *state = ArrayState::CommaOrEnd,
18✔
166
            }
167
        } else if self.root_started {
10✔
168
            self.root_complete = true;
10✔
169
        }
10✔
170
    }
46✔
171

NEW
172
    fn unexpected(&self, token: &SpannedAdapterToken<'de>, expected: &'static str) -> JsonError {
×
NEW
173
        JsonError::new(
×
NEW
174
            JsonErrorKind::UnexpectedToken {
×
NEW
175
                got: format!("{:?}", token.token),
×
NEW
176
                expected,
×
NEW
177
            },
×
NEW
178
            token.span,
×
179
        )
NEW
180
    }
×
181

NEW
182
    fn consume_value_tokens(&mut self) -> Result<(), JsonError> {
×
NEW
183
        let first = self.consume_token()?;
×
NEW
184
        match first.token {
×
NEW
185
            AdapterToken::ObjectStart => self.skip_container(DelimKind::Object),
×
NEW
186
            AdapterToken::ArrayStart => self.skip_container(DelimKind::Array),
×
187
            AdapterToken::ObjectEnd
188
            | AdapterToken::ArrayEnd
189
            | AdapterToken::Comma
NEW
190
            | AdapterToken::Colon => Err(self.unexpected(&first, "value")),
×
NEW
191
            AdapterToken::Eof => Err(JsonError::new(
×
NEW
192
                JsonErrorKind::UnexpectedEof { expected: "value" },
×
NEW
193
                first.span,
×
NEW
194
            )),
×
NEW
195
            _ => Ok(()),
×
196
        }
NEW
197
    }
×
198

NEW
199
    fn skip_container(&mut self, start_kind: DelimKind) -> Result<(), JsonError> {
×
NEW
200
        let mut stack = vec![start_kind];
×
NEW
201
        while let Some(current) = stack.last().copied() {
×
NEW
202
            let token = self.consume_token()?;
×
NEW
203
            match token.token {
×
NEW
204
                AdapterToken::ObjectStart => stack.push(DelimKind::Object),
×
NEW
205
                AdapterToken::ArrayStart => stack.push(DelimKind::Array),
×
206
                AdapterToken::ObjectEnd => {
NEW
207
                    if current != DelimKind::Object {
×
NEW
208
                        return Err(self.unexpected(&token, "'}'"));
×
NEW
209
                    }
×
NEW
210
                    stack.pop();
×
NEW
211
                    if stack.is_empty() {
×
NEW
212
                        break;
×
NEW
213
                    }
×
214
                }
215
                AdapterToken::ArrayEnd => {
NEW
216
                    if current != DelimKind::Array {
×
NEW
217
                        return Err(self.unexpected(&token, "']'"));
×
NEW
218
                    }
×
NEW
219
                    stack.pop();
×
NEW
220
                    if stack.is_empty() {
×
NEW
221
                        break;
×
NEW
222
                    }
×
223
                }
224
                AdapterToken::Eof => {
NEW
225
                    return Err(JsonError::new(
×
NEW
226
                        JsonErrorKind::UnexpectedEof { expected: "value" },
×
NEW
227
                        token.span,
×
NEW
228
                    ));
×
229
                }
NEW
230
                _ => {}
×
231
            }
232
        }
NEW
233
        Ok(())
×
NEW
234
    }
×
235

236
    fn determine_action(&self) -> NextAction {
100✔
237
        if let Some(context) = self.stack.last() {
100✔
238
            match context {
90✔
239
                ContextState::Object(state) => match state {
54✔
240
                    ObjectState::KeyOrEnd => NextAction::ObjectKey,
18✔
241
                    ObjectState::Value => NextAction::ObjectValue,
18✔
242
                    ObjectState::CommaOrEnd => NextAction::ObjectComma,
18✔
243
                },
244
                ContextState::Array(state) => match state {
36✔
245
                    ArrayState::ValueOrEnd => NextAction::ArrayValue,
18✔
246
                    ArrayState::CommaOrEnd => NextAction::ArrayComma,
18✔
247
                },
248
            }
249
        } else if self.root_complete {
10✔
NEW
250
            NextAction::RootFinished
×
251
        } else {
252
            NextAction::RootValue
10✔
253
        }
254
    }
100✔
255

256
    fn produce_event(&mut self) -> Result<ParseEvent<'de>, JsonError> {
80✔
257
        loop {
258
            match self.determine_action() {
100✔
259
                NextAction::ObjectKey => {
260
                    let token = self.consume_token()?;
18✔
261
                    match token.token {
18✔
262
                        AdapterToken::ObjectEnd => {
NEW
263
                            self.stack.pop();
×
NEW
264
                            self.finish_value_in_parent();
×
NEW
265
                            return Ok(ParseEvent::StructEnd);
×
266
                        }
267
                        AdapterToken::String(name) => {
18✔
268
                            self.expect_colon()?;
18✔
269
                            if let Some(ContextState::Object(state)) = self.stack.last_mut() {
18✔
270
                                *state = ObjectState::Value;
18✔
271
                            }
18✔
272
                            return Ok(ParseEvent::FieldKey(name, FieldLocationHint::KeyValue));
18✔
273
                        }
274
                        AdapterToken::Eof => {
NEW
275
                            return Err(JsonError::new(
×
NEW
276
                                JsonErrorKind::UnexpectedEof {
×
NEW
277
                                    expected: "field name or '}'",
×
NEW
278
                                },
×
NEW
279
                                token.span,
×
NEW
280
                            ));
×
281
                        }
NEW
282
                        _ => return Err(self.unexpected(&token, "field name or '}'")),
×
283
                    }
284
                }
285
                NextAction::ObjectValue => {
286
                    return self.parse_value_start_with_token(None);
18✔
287
                }
288
                NextAction::ObjectComma => {
289
                    let token = self.consume_token()?;
18✔
290
                    match token.token {
18✔
291
                        AdapterToken::Comma => {
292
                            if let Some(ContextState::Object(state)) = self.stack.last_mut() {
8✔
293
                                *state = ObjectState::KeyOrEnd;
8✔
294
                            }
8✔
295
                            continue;
8✔
296
                        }
297
                        AdapterToken::ObjectEnd => {
298
                            self.stack.pop();
10✔
299
                            self.finish_value_in_parent();
10✔
300
                            return Ok(ParseEvent::StructEnd);
10✔
301
                        }
302
                        AdapterToken::Eof => {
NEW
303
                            return Err(JsonError::new(
×
NEW
304
                                JsonErrorKind::UnexpectedEof {
×
NEW
305
                                    expected: "',' or '}'",
×
NEW
306
                                },
×
NEW
307
                                token.span,
×
NEW
308
                            ));
×
309
                        }
NEW
310
                        _ => return Err(self.unexpected(&token, "',' or '}'")),
×
311
                    }
312
                }
313
                NextAction::ArrayValue => {
314
                    let token = self.consume_token()?;
18✔
315
                    match token.token {
18✔
316
                        AdapterToken::ArrayEnd => {
NEW
317
                            self.stack.pop();
×
NEW
318
                            self.finish_value_in_parent();
×
NEW
319
                            return Ok(ParseEvent::SequenceEnd);
×
320
                        }
321
                        AdapterToken::Eof => {
NEW
322
                            return Err(JsonError::new(
×
NEW
323
                                JsonErrorKind::UnexpectedEof {
×
NEW
324
                                    expected: "value or ']'",
×
NEW
325
                                },
×
NEW
326
                                token.span,
×
NEW
327
                            ));
×
328
                        }
329
                        AdapterToken::Comma | AdapterToken::Colon => {
NEW
330
                            return Err(self.unexpected(&token, "value or ']'"));
×
331
                        }
332
                        _ => {
333
                            return self.parse_value_start_with_token(Some(token));
18✔
334
                        }
335
                    }
336
                }
337
                NextAction::ArrayComma => {
338
                    let token = self.consume_token()?;
18✔
339
                    match token.token {
18✔
340
                        AdapterToken::Comma => {
341
                            if let Some(ContextState::Array(state)) = self.stack.last_mut() {
12✔
342
                                *state = ArrayState::ValueOrEnd;
12✔
343
                            }
12✔
344
                            continue;
12✔
345
                        }
346
                        AdapterToken::ArrayEnd => {
347
                            self.stack.pop();
6✔
348
                            self.finish_value_in_parent();
6✔
349
                            return Ok(ParseEvent::SequenceEnd);
6✔
350
                        }
351
                        AdapterToken::Eof => {
NEW
352
                            return Err(JsonError::new(
×
NEW
353
                                JsonErrorKind::UnexpectedEof {
×
NEW
354
                                    expected: "',' or ']'",
×
NEW
355
                                },
×
NEW
356
                                token.span,
×
NEW
357
                            ));
×
358
                        }
NEW
359
                        _ => return Err(self.unexpected(&token, "',' or ']'")),
×
360
                    }
361
                }
362
                NextAction::RootValue => {
363
                    return self.parse_value_start_with_token(None);
10✔
364
                }
365
                NextAction::RootFinished => {
NEW
366
                    return Err(JsonError::without_span(JsonErrorKind::UnexpectedToken {
×
NEW
367
                        got: "end of input".into(),
×
NEW
368
                        expected: "no additional JSON values",
×
NEW
369
                    }));
×
370
                }
371
            }
372
        }
373
    }
80✔
374

NEW
375
    fn build_probe(&self) -> Result<Vec<FieldEvidence<'de>>, JsonError> {
×
NEW
376
        let remaining = self.input.get(self.current_offset..).unwrap_or_default();
×
NEW
377
        if remaining.is_empty() {
×
NEW
378
            return Ok(Vec::new());
×
NEW
379
        }
×
380

NEW
381
        let mut adapter = SliceAdapter::<true>::new(remaining);
×
NEW
382
        let first = adapter.next_token().map_err(JsonError::from)?;
×
NEW
383
        if !matches!(first.token, AdapterToken::ObjectStart) {
×
NEW
384
            return Ok(Vec::new());
×
NEW
385
        }
×
386

NEW
387
        let mut evidence = Vec::new();
×
388
        loop {
NEW
389
            let token = adapter.next_token().map_err(JsonError::from)?;
×
NEW
390
            match token.token {
×
NEW
391
                AdapterToken::ObjectEnd => break,
×
NEW
392
                AdapterToken::String(name) => {
×
NEW
393
                    let colon = adapter.next_token().map_err(JsonError::from)?;
×
NEW
394
                    if !matches!(colon.token, AdapterToken::Colon) {
×
NEW
395
                        return Err(JsonError::new(
×
NEW
396
                            JsonErrorKind::UnexpectedToken {
×
NEW
397
                                got: format!("{:?}", colon.token),
×
NEW
398
                                expected: "':'",
×
NEW
399
                            },
×
NEW
400
                            colon.span,
×
NEW
401
                        ));
×
NEW
402
                    }
×
403

NEW
404
                    evidence.push(FieldEvidence::new(name, FieldLocationHint::KeyValue, None));
×
405

NEW
406
                    adapter.skip().map_err(JsonError::from)?;
×
407

NEW
408
                    let sep = adapter.next_token().map_err(JsonError::from)?;
×
NEW
409
                    match sep.token {
×
NEW
410
                        AdapterToken::Comma => continue,
×
NEW
411
                        AdapterToken::ObjectEnd => break,
×
412
                        AdapterToken::Eof => {
NEW
413
                            return Err(JsonError::new(
×
NEW
414
                                JsonErrorKind::UnexpectedEof {
×
NEW
415
                                    expected: "',' or '}'",
×
NEW
416
                                },
×
NEW
417
                                sep.span,
×
NEW
418
                            ));
×
419
                        }
420
                        _ => {
NEW
421
                            return Err(JsonError::new(
×
NEW
422
                                JsonErrorKind::UnexpectedToken {
×
NEW
423
                                    got: format!("{:?}", sep.token),
×
NEW
424
                                    expected: "',' or '}'",
×
NEW
425
                                },
×
NEW
426
                                sep.span,
×
NEW
427
                            ));
×
428
                        }
429
                    }
430
                }
431
                AdapterToken::Eof => {
NEW
432
                    return Err(JsonError::new(
×
NEW
433
                        JsonErrorKind::UnexpectedEof {
×
NEW
434
                            expected: "field name or '}'",
×
NEW
435
                        },
×
NEW
436
                        token.span,
×
NEW
437
                    ));
×
438
                }
439
                _ => {
NEW
440
                    return Err(JsonError::new(
×
NEW
441
                        JsonErrorKind::UnexpectedToken {
×
NEW
442
                            got: format!("{:?}", token.token),
×
NEW
443
                            expected: "field name or '}'",
×
NEW
444
                        },
×
NEW
445
                        token.span,
×
NEW
446
                    ));
×
447
                }
448
            }
449
        }
450

NEW
451
        Ok(evidence)
×
NEW
452
    }
×
453
}
454

455
impl<'de> FormatParser<'de> for JsonParser<'de> {
456
    type Error = JsonError;
457
    type Probe<'a>
458
        = JsonProbe<'de>
459
    where
460
        Self: 'a;
461

462
    fn next_event(&mut self) -> Result<ParseEvent<'de>, Self::Error> {
80✔
463
        if let Some(event) = self.event_peek.take() {
80✔
NEW
464
            return Ok(event);
×
465
        }
80✔
466
        self.produce_event()
80✔
467
    }
80✔
468

NEW
469
    fn peek_event(&mut self) -> Result<ParseEvent<'de>, Self::Error> {
×
NEW
470
        if let Some(event) = self.event_peek.clone() {
×
NEW
471
            return Ok(event);
×
NEW
472
        }
×
NEW
473
        let event = self.produce_event()?;
×
NEW
474
        self.event_peek = Some(event.clone());
×
NEW
475
        Ok(event)
×
NEW
476
    }
×
477

NEW
478
    fn skip_value(&mut self) -> Result<(), Self::Error> {
×
NEW
479
        debug_assert!(
×
NEW
480
            self.event_peek.is_none(),
×
481
            "skip_value called while an event is buffered"
482
        );
NEW
483
        self.consume_value_tokens()?;
×
NEW
484
        self.finish_value_in_parent();
×
NEW
485
        Ok(())
×
NEW
486
    }
×
487

NEW
488
    fn begin_probe(&mut self) -> Result<Self::Probe<'_>, Self::Error> {
×
NEW
489
        let evidence = self.build_probe()?;
×
NEW
490
        Ok(JsonProbe { evidence, idx: 0 })
×
NEW
491
    }
×
492
}
493

494
pub struct JsonProbe<'de> {
495
    evidence: Vec<FieldEvidence<'de>>,
496
    idx: usize,
497
}
498

499
impl<'de> ProbeStream<'de> for JsonProbe<'de> {
500
    type Error = JsonError;
501

NEW
502
    fn next(&mut self) -> Result<Option<FieldEvidence<'de>>, Self::Error> {
×
NEW
503
        if self.idx >= self.evidence.len() {
×
NEW
504
            Ok(None)
×
505
        } else {
NEW
506
            let ev = self.evidence[self.idx].clone();
×
NEW
507
            self.idx += 1;
×
NEW
508
            Ok(Some(ev))
×
509
        }
NEW
510
    }
×
511
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc