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

kaidokert / picojson-rs / 16296752393

15 Jul 2025 02:54PM UTC coverage: 91.544% (-2.2%) from 93.785%
16296752393

Pull #57

github

web-flow
Merge cdc45a9eb into 6be34a4b2
Pull Request #57: Even bigger refactor

481 of 649 new or added lines in 10 files covered. (74.11%)

17 existing lines in 5 files now uncovered.

4742 of 5180 relevant lines covered (91.54%)

739.86 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> {
×
167
        use crate::slice_input_buffer::InputBuffer;
NEW
168
        match self.content_builder.buffer_mut().consume_byte() {
×
UNCOV
169
            Ok(byte) => Ok(Some(byte)),
×
UNCOV
170
            Err(crate::slice_input_buffer::Error::ReachedEnd) => Ok(None),
×
171
            Err(err) => Err(err.into()),
×
172
        }
UNCOV
173
    }
×
174
}
175

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

488
    #[test]
489
    fn test_unicode_escape_integration() {
1✔
490
        let input = r#"{"key": "Hello\u0041World"}"#; // \u0041 = 'A'
1✔
491

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