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

kaidokert / picojson-rs / 16297821328

15 Jul 2025 03:38PM UTC coverage: 93.249% (-0.6%) from 93.865%
16297821328

Pull #59

github

web-flow
Merge 583198908 into 1dbca311e
Pull Request #59: Big refactor

471 of 544 new or added lines in 8 files covered. (86.58%)

14 existing lines in 4 files now uncovered.

4738 of 5081 relevant lines covered (93.25%)

728.0 hits per line

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

90.67
/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
        self.parser_core.next_event_impl_unified(
316✔
150
            &mut self.content_builder,
316✔
151
            crate::parser_core::EscapeTiming::OnBegin,
316✔
152
        )
153
    }
316✔
154
}
155

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

366
        assert_eq!(parser.next_event(), Ok(Event::StartObject));
1✔
367

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

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

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

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

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

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

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

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

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

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

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

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

457
        assert_eq!(parser.next_event(), Ok(Event::StartArray));
1✔
458

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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