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

kaidokert / picojson-rs / 16309731743

16 Jul 2025 03:35AM UTC coverage: 94.287% (+0.4%) from 93.864%
16309731743

Pull #60

github

web-flow
Merge eb993d70a into d7962e604
Pull Request #60: Clean refactor

504 of 541 new or added lines in 9 files covered. (93.16%)

5 existing lines in 2 files now uncovered.

4704 of 4989 relevant lines covered (94.29%)

741.71 hits per line

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

90.7
/picojson/src/slice_parser.rs
1
// SPDX-License-Identifier: Apache-2.0
2

3
use crate::parse_error::ParseError;
4
use crate::parser_core::ParserCore;
5
use crate::shared::{Event, PullParser};
6
use crate::slice_content_builder::SliceContentBuilder;
7
use crate::slice_input_buffer::InputBuffer;
8
use crate::ujson;
9

10
use ujson::{BitStackConfig, DefaultConfig};
11

12
/// A pull parser that parses JSON from a slice.
13
///
14
/// Generic over BitStack storage type for configurable nesting depth.
15
// Lifetime 'a is the input buffer lifetime
16
// lifetime 'b is the scratch/copy buffer lifetime
17
pub struct SliceParser<'a, 'b, C: BitStackConfig = DefaultConfig> {
18
    /// The shared parser core that handles the unified event processing loop
19
    parser_core: ParserCore<C::Bucket, C::Counter>,
20
    /// The content builder that handles SliceParser-specific content extraction
21
    content_builder: SliceContentBuilder<'a, 'b>,
22
}
23

24
/// Methods for the pull parser.
25
impl<'a> SliceParser<'a, '_, DefaultConfig> {
26
    /// Creates a new parser for the given JSON input.
27
    ///
28
    /// This parser assumes no string escapes will be encountered. If escapes are found,
29
    /// parsing will fail with `ScratchBufferFull` error.
30
    ///
31
    /// For JSON with potential string escapes, use `with_buffer()` instead.
32
    ///
33
    /// # Arguments
34
    /// * `input` - A string slice containing the JSON data to be parsed.
35
    ///
36
    /// # Example
37
    /// ```
38
    /// use picojson::SliceParser;
39
    /// let parser = SliceParser::new(r#"{"name": "value"}"#);
40
    /// ```
41
    pub fn new(input: &'a str) -> Self {
9✔
42
        Self::new_from_slice(input.as_bytes())
9✔
43
    }
9✔
44

45
    /// Creates a new parser from a byte slice.
46
    ///
47
    /// Assumes no string escapes will be encountered. For JSON with escapes, use [`with_buffer_from_slice`].
48
    ///
49
    /// # Example
50
    /// ```
51
    /// # use picojson::SliceParser;
52
    /// let parser = SliceParser::new_from_slice(br#"{"name": "value"}"#);
53
    /// ```
54
    ///
55
    /// [`with_buffer_from_slice`]: Self::with_buffer_from_slice
56
    pub fn new_from_slice(input: &'a [u8]) -> Self {
9✔
57
        Self::with_config_from_slice(input)
9✔
58
    }
9✔
59
}
60

61
/// Constructor with scratch buffer for SliceParser using DefaultConfig
62
impl<'a, 'b> SliceParser<'a, 'b, DefaultConfig> {
63
    /// Creates a new parser for the given JSON input with external scratch buffer.
64
    ///
65
    /// Use this when your JSON contains string escapes (like `\n`, `\"`, `\u0041`) that
66
    /// need to be unescaped during parsing.
67
    ///
68
    /// # Arguments
69
    /// * `input` - A string slice containing the JSON data to be parsed.
70
    /// * `scratch_buffer` - A mutable byte slice for temporary string unescaping operations.
71
    ///   This buffer needs to be at least as long as the longest
72
    ///   contiguous token (string, key, number) in the input.
73
    ///
74
    /// # Example
75
    /// ```
76
    /// use picojson::SliceParser;
77
    /// let mut scratch = [0u8; 1024];
78
    /// let parser = SliceParser::with_buffer(r#"{"msg": "Hello\nWorld"}"#, &mut scratch);
79
    /// ```
80
    pub fn with_buffer(input: &'a str, scratch_buffer: &'b mut [u8]) -> Self {
42✔
81
        Self::with_buffer_from_slice(input.as_bytes(), scratch_buffer)
42✔
82
    }
42✔
83

84
    /// Creates a new parser from a byte slice with a scratch buffer.
85
    ///
86
    /// Use when JSON contains string escapes that need unescaping.
87
    ///
88
    /// # Example
89
    /// ```
90
    /// # use picojson::SliceParser;
91
    /// let mut scratch = [0u8; 1024];
92
    /// let parser = SliceParser::with_buffer_from_slice(br#"{"msg": "Hello\nWorld"}"#, &mut scratch);
93
    /// ```
94
    pub fn with_buffer_from_slice(input: &'a [u8], scratch_buffer: &'b mut [u8]) -> Self {
43✔
95
        Self::with_config_and_buffer_from_slice(input, scratch_buffer)
43✔
96
    }
43✔
97
}
98

99
/// Generic constructor for SliceParser with custom configurations
100
impl<'a, 'b, C: BitStackConfig> SliceParser<'a, 'b, C> {
101
    /// Creates a new parser with a custom `BitStackConfig`.
102
    ///
103
    /// This parser assumes no string escapes will be encountered. If escapes are found,
104
    /// parsing will fail. For JSON with escapes, use `with_config_and_buffer`.
105
    pub fn with_config(input: &'a str) -> Self {
1✔
106
        Self::with_config_from_slice(input.as_bytes())
1✔
107
    }
1✔
108

109
    /// Creates a new parser from a byte slice with a custom `BitStackConfig`.
110
    ///
111
    /// Assumes no string escapes will be encountered. For JSON with escapes, use [`with_config_and_buffer_from_slice`].
112
    ///
113
    /// [`with_config_and_buffer_from_slice`]: Self::with_config_and_buffer_from_slice
114
    pub fn with_config_from_slice(input: &'a [u8]) -> Self {
10✔
115
        Self::with_config_and_buffer_from_slice(input, &mut [])
10✔
116
    }
10✔
117

118
    /// Creates a new parser with a custom `BitStackConfig` and a user-provided scratch buffer.
119
    ///
120
    /// Use this when your JSON contains string escapes (like `\n`, `\"`, `\u0041`).
121
    ///
122
    /// # Arguments
123
    /// * `input` - A string slice containing the JSON data to be parsed.
124
    /// * `scratch_buffer` - A mutable byte slice for temporary string unescaping operations.
125
    ///   This buffer needs to be at least as long as the longest
126
    ///   contiguous token (string, key, number) in the input.
127
    pub fn with_config_and_buffer(input: &'a str, scratch_buffer: &'b mut [u8]) -> Self {
2✔
128
        Self::with_config_and_buffer_from_slice(input.as_bytes(), scratch_buffer)
2✔
129
    }
2✔
130

131
    /// Creates a new parser from a byte slice with a custom `BitStackConfig` and scratch buffer.
132
    ///
133
    /// Use when JSON contains string escapes that need unescaping.
134
    /// This is the core constructor that all other constructors delegate to.
135
    pub fn with_config_and_buffer_from_slice(
55✔
136
        input: &'a [u8],
55✔
137
        scratch_buffer: &'b mut [u8],
55✔
138
    ) -> Self {
55✔
139
        SliceParser {
55✔
140
            parser_core: ParserCore::new(),
55✔
141
            content_builder: SliceContentBuilder::new(input, scratch_buffer),
55✔
142
        }
55✔
143
    }
55✔
144

145
    /// Returns the next JSON event or an error if parsing fails.
146
    /// Parsing continues until `EndDocument` is returned or an error occurs.
147
    fn next_event_impl(&mut self) -> Result<Event<'_, '_>, ParseError> {
316✔
148
        // Use the unified ParserCore implementation with SliceParser-specific timing
149
        // No byte accumulation needed for SliceParser (pass no-op closure)
150
        self.parser_core.next_event_impl(
316✔
151
            &mut self.content_builder,
316✔
152
            crate::parser_core::EscapeTiming::OnBegin,
316✔
153
            |_, _| Ok(()),
1,571✔
154
        )
155
    }
316✔
156
}
157

158
impl<C: BitStackConfig> PullParser for SliceParser<'_, '_, C> {
159
    fn next_event(&mut self) -> Result<Event<'_, '_>, ParseError> {
318✔
160
        if self.content_builder.buffer().is_past_end() {
318✔
161
            return Ok(Event::EndDocument);
2✔
162
        }
316✔
163
        self.next_event_impl()
316✔
164
    }
318✔
165
}
166

167
impl<C: BitStackConfig> crate::shared::ByteProvider for SliceParser<'_, '_, C> {
UNCOV
168
    fn next_byte(&mut self) -> Result<Option<u8>, ParseError> {
×
NEW
169
        match self.content_builder.buffer_mut().consume_byte() {
×
UNCOV
170
            Ok(byte) => Ok(Some(byte)),
×
UNCOV
171
            Err(crate::slice_input_buffer::Error::ReachedEnd) => Ok(None),
×
172
            Err(err) => Err(err.into()),
×
173
        }
UNCOV
174
    }
×
175
}
176

177
#[cfg(test)]
178
mod tests {
179
    use super::*;
180
    use crate::{ArrayBitStack, BitStackStruct, String};
181

182
    #[test]
183
    fn make_parser() {
1✔
184
        let input = r#"{"key": "value"}"#;
1✔
185
        let mut scratch = [0u8; 1024];
1✔
186
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
187
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
188
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
189
        assert_eq!(
1✔
190
            parser.next_event(),
1✔
191
            Ok(Event::String(String::Borrowed("value")))
192
        );
193
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
194
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
195
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
196
    }
1✔
197

198
    #[test]
199
    fn parse_number() {
1✔
200
        let input = r#"{"key": 124}"#;
1✔
201
        let mut scratch = [0u8; 1024];
1✔
202
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
203
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
204
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
205
        // Check number value using new JsonNumber API
206
        match parser.next_event() {
1✔
207
            Ok(Event::Number(num)) => {
1✔
208
                assert_eq!(num.as_str(), "124");
1✔
209
                assert_eq!(num.as_int(), Some(124));
1✔
210
            }
211
            other => panic!("Expected Number, got: {:?}", other),
×
212
        }
213
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
214
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
215
    }
1✔
216

217
    #[test]
218
    fn parse_bool_and_null() {
1✔
219
        let input = r#"{"key": true, "key2": false, "key3": null}"#;
1✔
220
        let mut scratch = [0u8; 1024];
1✔
221
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
222
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
223
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
224
        assert_eq!(parser.next_event(), Ok(Event::Bool(true)));
1✔
225
        assert_eq!(
1✔
226
            parser.next_event(),
1✔
227
            Ok(Event::Key(String::Borrowed("key2")))
228
        );
229
        assert_eq!(parser.next_event(), Ok(Event::Bool(false)));
1✔
230
        assert_eq!(
1✔
231
            parser.next_event(),
1✔
232
            Ok(Event::Key(String::Borrowed("key3")))
233
        );
234
        assert_eq!(parser.next_event(), Ok(Event::Null));
1✔
235
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
236
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
237
    }
1✔
238

239
    #[test]
240
    fn parse_array() {
1✔
241
        #[cfg(feature = "float-error")]
242
        let input = r#"{"key": [1, 2, 3]}"#; // No floats for float-error config
243
        #[cfg(not(feature = "float-error"))]
244
        let input = r#"{"key": [1, 2.2, 3]}"#; // Include float for other configs
1✔
245

246
        let mut scratch = [0u8; 1024];
1✔
247
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
248
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
249
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
250
        assert_eq!(parser.next_event(), Ok(Event::StartArray));
1✔
251

252
        // First number: 1 (integer)
253
        match parser.next_event() {
1✔
254
            Ok(Event::Number(num)) => {
1✔
255
                assert_eq!(num.as_str(), "1");
1✔
256
                assert_eq!(num.as_int(), Some(1));
1✔
257
            }
258
            other => panic!("Expected Number(1), got: {:?}", other),
×
259
        }
260

261
        // Second number: depends on configuration
262
        match parser.next_event() {
1✔
263
            Ok(Event::Number(num)) => {
1✔
264
                #[cfg(feature = "float-error")]
265
                {
266
                    assert_eq!(num.as_str(), "2");
267
                    assert_eq!(num.as_int(), Some(2));
268
                }
269
                #[cfg(not(feature = "float-error"))]
270
                {
271
                    assert_eq!(num.as_str(), "2.2");
1✔
272
                    #[cfg(feature = "float")]
273
                    assert_eq!(num.as_f64(), Some(2.2));
1✔
274
                    #[cfg(not(feature = "float-error"))]
275
                    assert!(num.is_float());
1✔
276
                }
277
            }
278
            other => panic!("Expected Number, got: {:?}", other),
×
279
        }
280

281
        // Third number: 3 (integer)
282
        match parser.next_event() {
1✔
283
            Ok(Event::Number(num)) => {
1✔
284
                assert_eq!(num.as_str(), "3");
1✔
285
                assert_eq!(num.as_int(), Some(3));
1✔
286
            }
287
            other => panic!("Expected Number(3), got: {:?}", other),
×
288
        }
289

290
        assert_eq!(parser.next_event(), Ok(Event::EndArray));
1✔
291
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
292
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
293
    }
1✔
294

295
    #[test]
296
    fn test_simple_parser_api() {
1✔
297
        let input = r#"{"name": "test"}"#;
1✔
298
        let mut scratch = [0u8; 1024];
1✔
299
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
300

301
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
302
        assert_eq!(
1✔
303
            parser.next_event(),
1✔
304
            Ok(Event::Key(String::Borrowed("name")))
305
        );
306
        assert_eq!(
1✔
307
            parser.next_event(),
1✔
308
            Ok(Event::String(String::Borrowed("test")))
309
        );
310
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
311
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
312
    }
1✔
313

314
    #[test]
315
    fn test_parser_with_escaped_strings() {
1✔
316
        // Use regular string literal to properly include escape sequences
317
        let input = "{\"name\": \"John\\nDoe\", \"message\": \"Hello\\tWorld!\"}";
1✔
318
        let mut scratch = [0u8; 1024];
1✔
319
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
320

321
        // Test that the parser correctly handles escaped strings
322
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
323

324
        // Key should be simple (no escapes) -> Borrowed
325
        if let Ok(Event::Key(key)) = parser.next_event() {
1✔
326
            assert_eq!(&*key, "name");
1✔
327
            // This should be the fast path (borrowed)
328
            assert!(matches!(key, String::Borrowed(_)));
1✔
329
        } else {
330
            panic!("Expected Key event");
×
331
        }
332

333
        // Value should have escapes -> Unescaped
334
        if let Ok(Event::String(value)) = parser.next_event() {
1✔
335
            assert_eq!(&*value, "John\nDoe");
1✔
336
            // This should be the slow path (unescaped)
337
            assert!(matches!(value, String::Unescaped(_)));
1✔
338
        } else {
339
            panic!("Expected String event");
×
340
        }
341

342
        // Second key should be simple -> Borrowed
343
        if let Ok(Event::Key(key)) = parser.next_event() {
1✔
344
            assert_eq!(&*key, "message");
1✔
345
            assert!(matches!(key, String::Borrowed(_)));
1✔
346
        } else {
347
            panic!("Expected Key event");
×
348
        }
349

350
        // Second value should have escapes -> Unescaped
351
        if let Ok(Event::String(value)) = parser.next_event() {
1✔
352
            assert_eq!(&*value, "Hello\tWorld!");
1✔
353
            assert!(matches!(value, String::Unescaped(_)));
1✔
354
        } else {
355
            panic!("Expected String event");
×
356
        }
357

358
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
359
    }
1✔
360

361
    #[test]
362
    fn test_copy_on_escape_optimization() {
1✔
363
        // Use regular string literal to include proper escape sequences
364
        let input = "{\"simple\": \"no escapes\", \"complex\": \"has\\nescapes\"}";
1✔
365
        let mut scratch = [0u8; 1024];
1✔
366
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
367

368
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
369

370
        // "simple" key should be borrowed (fast path)
371
        if let Ok(Event::Key(key)) = parser.next_event() {
1✔
372
            assert_eq!(&*key, "simple");
1✔
373
            assert!(matches!(key, String::Borrowed(_)));
1✔
374
        } else {
375
            panic!("Expected Key event");
×
376
        }
377

378
        // "no escapes" value should be borrowed (fast path)
379
        if let Ok(Event::String(value)) = parser.next_event() {
1✔
380
            assert_eq!(&*value, "no escapes");
1✔
381
            assert!(matches!(value, String::Borrowed(_)));
1✔
382
        } else {
383
            panic!("Expected String event");
×
384
        }
385

386
        // "complex" key should be borrowed (fast path)
387
        if let Ok(Event::Key(key)) = parser.next_event() {
1✔
388
            assert_eq!(&*key, "complex");
1✔
389
            assert!(matches!(key, String::Borrowed(_)));
1✔
390
        } else {
391
            panic!("Expected Key event");
×
392
        }
393

394
        // "has\\nescapes" value should be unescaped (slow path)
395
        if let Ok(Event::String(value)) = parser.next_event() {
1✔
396
            assert_eq!(&*value, "has\nescapes");
1✔
397
            assert!(matches!(value, String::Unescaped(_)));
1✔
398
        } else {
399
            panic!("Expected String event");
×
400
        }
401

402
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
403
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
404
    }
1✔
405

406
    #[test]
407
    fn test_coe2_integration_multiple_escapes() {
1✔
408
        let input = r#"{"key": "a\nb\tc\rd"}"#;
1✔
409
        let mut scratch = [0u8; 1024];
1✔
410
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
411

412
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
413
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
414

415
        let string_event = parser.next_event().unwrap();
1✔
416
        match string_event {
1✔
417
            Event::String(String::Unescaped(s)) => {
1✔
418
                assert_eq!(s, "a\nb\tc\rd");
1✔
419
            }
420
            _ => panic!("Expected unescaped string value, got: {:?}", string_event),
×
421
        }
422
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
423
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
424
    }
1✔
425

426
    #[test]
427
    fn test_coe2_integration_zero_copy_path() {
1✔
428
        let input = r#"{"simple": "no_escapes_here"}"#;
1✔
429
        let mut scratch = [0u8; 1024];
1✔
430
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
431

432
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
433
        assert_eq!(
1✔
434
            parser.next_event(),
1✔
435
            Ok(Event::Key(String::Borrowed("simple")))
436
        );
437

438
        // This should be borrowed (zero-copy) since no escapes
439
        let string_event = parser.next_event().unwrap();
1✔
440
        match string_event {
1✔
441
            Event::String(String::Borrowed(s)) => {
1✔
442
                assert_eq!(s, "no_escapes_here");
1✔
443
            }
444
            _ => panic!(
×
445
                "Expected borrowed string value for zero-copy, got: {:?}",
×
446
                string_event
447
            ),
448
        }
449
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
450
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
451
    }
1✔
452

453
    #[test]
454
    fn test_coe2_integration_mixed_strings() {
1✔
455
        let input = r#"["plain", "with\nescapes", "plain2", "more\tescapes"]"#;
1✔
456
        let mut scratch = [0u8; 1024];
1✔
457
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
458

459
        assert_eq!(parser.next_event(), Ok(Event::StartArray));
1✔
460

461
        // First string: no escapes -> borrowed
462
        match parser.next_event().unwrap() {
1✔
463
            Event::String(String::Borrowed(s)) => assert_eq!(s, "plain"),
1✔
464
            other => panic!("Expected borrowed string, got: {:?}", other),
×
465
        }
466

467
        // Second string: has escapes -> unescaped
468
        match parser.next_event().unwrap() {
1✔
469
            Event::String(String::Unescaped(s)) => assert_eq!(s, "with\nescapes"),
1✔
470
            other => panic!("Expected unescaped string, got: {:?}", other),
×
471
        }
472

473
        // Third string: no escapes -> borrowed
474
        match parser.next_event().unwrap() {
1✔
475
            Event::String(String::Borrowed(s)) => assert_eq!(s, "plain2"),
1✔
476
            other => panic!("Expected borrowed string, got: {:?}", other),
×
477
        }
478

479
        // Fourth string: has escapes -> unescaped
480
        match parser.next_event().unwrap() {
1✔
481
            Event::String(String::Unescaped(s)) => assert_eq!(s, "more\tescapes"),
1✔
482
            other => panic!("Expected unescaped string, got: {:?}", other),
×
483
        }
484

485
        assert_eq!(parser.next_event(), Ok(Event::EndArray));
1✔
486
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
487
    }
1✔
488

489
    #[test]
490
    fn test_unicode_escape_integration() {
1✔
491
        let input = r#"{"key": "Hello\u0041World"}"#; // \u0041 = 'A'
1✔
492
        let mut scratch = [0u8; 1024];
1✔
493
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
494

495
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
496
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
497

498
        // The string with Unicode escape should be unescaped
499
        match parser.next_event().unwrap() {
1✔
500
            Event::String(String::Unescaped(s)) => {
1✔
501
                assert_eq!(s, "HelloAWorld");
1✔
502
            }
503
            other => panic!("Expected unescaped string value, got: {:?}", other),
×
504
        }
505

506
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
507
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
508
    }
1✔
509

510
    #[test]
511
    fn test_original_parser_escape_trace() {
1✔
512
        // Test escape sequence processing with logging
513
        let input = r#""a\nb""#;
1✔
514
        let mut scratch = [0u8; 1024];
1✔
515
        let mut parser = SliceParser::with_buffer(input, &mut scratch);
1✔
516

517
        // Should get String with unescaped content
518
        let event = parser.next_event().unwrap();
1✔
519
        if let Event::String(s) = event {
1✔
520
            assert_eq!(&*s, "a\nb");
1✔
521
        } else {
522
            panic!("Expected String event, got {:?}", event);
×
523
        }
524

525
        // Should get EndDocument
526
        let event = parser.next_event().unwrap();
1✔
527
        assert_eq!(event, Event::EndDocument);
1✔
528
    }
1✔
529

530
    #[test]
531
    fn make_parser_from_slice() {
1✔
532
        let input = br#"{"key": "value"}"#;
1✔
533
        let mut scratch = [0u8; 1024];
1✔
534
        let mut parser = SliceParser::with_buffer_from_slice(input, &mut scratch);
1✔
535
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
536
        assert_eq!(parser.next_event(), Ok(Event::Key(String::Borrowed("key"))));
1✔
537
        assert_eq!(
1✔
538
            parser.next_event(),
1✔
539
            Ok(Event::String(String::Borrowed("value")))
540
        );
541
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
542
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
543
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
544
    }
1✔
545

546
    #[test]
547
    fn test_with_config_constructors() {
1✔
548
        // Test with_config constructor (no escapes)
549
        let json = r#"{"simple": "no_escapes"}"#;
1✔
550
        let mut parser = SliceParser::<BitStackStruct<u64, u16>>::with_config(json);
1✔
551

552
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
553
        assert_eq!(
1✔
554
            parser.next_event(),
1✔
555
            Ok(Event::Key(String::Borrowed("simple")))
556
        );
557
        assert_eq!(
1✔
558
            parser.next_event(),
1✔
559
            Ok(Event::String(String::Borrowed("no_escapes")))
560
        );
561
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
562
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
563
    }
1✔
564

565
    #[test]
566
    fn test_with_config_and_buffer_constructors() {
1✔
567
        // Test with_config_and_buffer constructor (with escapes)
568
        let json = r#"{"escaped": "hello\nworld"}"#;
1✔
569
        let mut scratch = [0u8; 64];
1✔
570
        let mut parser =
1✔
571
            SliceParser::<BitStackStruct<u64, u16>>::with_config_and_buffer(json, &mut scratch);
1✔
572

573
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
574
        assert_eq!(
1✔
575
            parser.next_event(),
1✔
576
            Ok(Event::Key(String::Borrowed("escaped")))
577
        );
578

579
        if let Ok(Event::String(s)) = parser.next_event() {
1✔
580
            assert_eq!(s.as_ref(), "hello\nworld"); // Escape should be processed
1✔
581
        } else {
582
            panic!("Expected String event");
×
583
        }
584

585
        assert_eq!(parser.next_event(), Ok(Event::EndObject));
1✔
586
        assert_eq!(parser.next_event(), Ok(Event::EndDocument));
1✔
587
    }
1✔
588

589
    #[test]
590
    fn test_alternative_config_deep_nesting() {
1✔
591
        // Test that custom BitStack configs can handle deeper nesting
592
        let json = r#"{"a":{"b":{"c":{"d":{"e":"deep"}}}}}"#;
1✔
593
        let mut scratch = [0u8; 64];
1✔
594
        let mut parser =
1✔
595
            SliceParser::<ArrayBitStack<8, u32, u16>>::with_config_and_buffer(json, &mut scratch);
1✔
596

597
        // Parse the deep structure
598
        let mut depth = 0;
1✔
599
        while let Ok(event) = parser.next_event() {
17✔
600
            match event {
17✔
601
                Event::StartObject => depth += 1,
5✔
602
                Event::EndObject => depth -= 1,
5✔
603
                Event::EndDocument => break,
1✔
604
                _ => {}
6✔
605
            }
606
        }
607

608
        // Should have successfully parsed a 5-level deep structure
609
        assert_eq!(depth, 0); // All objects should be closed
1✔
610
    }
1✔
611
}
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