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

kaidokert / picojson-rs / 16239454628

12 Jul 2025 03:29PM UTC coverage: 94.234% (+0.5%) from 93.685%
16239454628

Pull #53

github

web-flow
Merge a5de05240 into 1db0180ce
Pull Request #53: Big refactor step 1

433 of 447 new or added lines in 3 files covered. (96.87%)

1 existing line in 1 file now uncovered.

4658 of 4943 relevant lines covered (94.23%)

624.61 hits per line

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

87.98
/picojson/src/stream_parser.rs
1
// SPDX-License-Identifier: Apache-2.0
2

3
use crate::escape_processor::UnicodeEscapeCollector;
4
use crate::event_processor::{
5
    clear_events, create_tokenizer_callback, have_events, process_begin_events,
6
    process_simple_escape_event, process_simple_events, process_unicode_escape_events,
7
    take_first_event, ContentExtractor, EscapeHandler, EventResult, ParserContext,
8
};
9
use crate::parse_error::ParseError;
10
use crate::shared::{ContentRange, Event, ParserState, UnexpectedState};
11
use crate::stream_buffer::StreamBuffer;
12
use crate::{ujson, PullParser};
13
use ujson::{EventToken, Tokenizer};
14

15
use ujson::{BitStackConfig, DefaultConfig};
16

17
/// Trait for input sources that can provide data to the streaming parser.
18
pub trait Reader {
19
    /// The error type returned by read operations
20
    type Error;
21

22
    /// Read data into the provided buffer.
23
    /// Returns the number of bytes read, or an error.
24
    ///
25
    /// # Contract
26
    /// - A return value of 0 **MUST** indicate true end of stream
27
    /// - Implementations **MUST NOT** return 0 unless no more data will ever be available
28
    /// - Returning 0 followed by non-zero reads in subsequent calls violates this contract
29
    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
30
}
31

32
/// Represents the processing state of the StreamParser
33
/// Enforces logical invariants: once Finished, no other processing states are possible
34
#[derive(Debug)]
35
enum ProcessingState {
36
    /// Normal active processing
37
    Active {
38
        unescaped_reset_queued: bool,
39
        in_escape_sequence: bool,
40
    },
41
    /// All input consumed, tokenizer finished
42
    Finished,
43
}
44

45
/// A pull parser that parses JSON from a stream.
46
///
47
/// Generic over BitStackConfig for configurable nesting depth.
48
/// It is designed to be used with the [Reader] trait, which is used to read data from a stream.
49
///
50
pub struct StreamParser<'b, R: Reader, C: BitStackConfig = DefaultConfig> {
51
    /// The tokenizer that processes JSON tokens
52
    tokenizer: Tokenizer<C::Bucket, C::Counter>,
53
    /// Parser state tracking
54
    parser_state: ParserState,
55
    /// Reader for streaming input
56
    reader: R,
57
    /// StreamBuffer for single-buffer input and escape processing
58
    stream_buffer: StreamBuffer<'b>,
59

60
    /// Processing state machine that enforces logical invariants
61
    processing_state: ProcessingState,
62

63
    /// Shared Unicode escape collector for \uXXXX sequences
64
    unicode_escape_collector: UnicodeEscapeCollector,
65
}
66

67
/// Methods for StreamParser using DefaultConfig
68
impl<'b, R: Reader> StreamParser<'b, R, DefaultConfig> {
69
    /// Create a new StreamParser with default configuration
70
    ///
71
    /// Uses the default BitStack configuration (u32 bucket, u8 counter)
72
    /// for most common use cases.
73
    pub fn new(reader: R, buffer: &'b mut [u8]) -> Self {
1,035✔
74
        Self::with_config(reader, buffer)
1,035✔
75
    }
1,035✔
76
}
77

78
/// Methods for StreamParser with custom BitStackConfig
79
impl<'b, R: Reader, C: BitStackConfig> StreamParser<'b, R, C> {
80
    /// Create a new StreamParser with custom configuration
81
    ///
82
    /// Use this when you need custom BitStack storage types for specific
83
    /// memory or nesting depth requirements.
84
    ///
85
    /// # Example
86
    /// ```
87
    /// use picojson::{StreamParser, BitStackStruct, ChunkReader};
88
    ///
89
    /// let json = b"{\"test\": 42}";
90
    /// // For testing, ChunkReader is a convenient Reader implementation
91
    /// let reader = ChunkReader::new(json, 10);
92
    /// let mut buffer = [0u8; 256];
93
    ///
94
    /// // Custom configuration: u64 bucket + u16 counter for deeper nesting
95
    /// let mut parser = StreamParser::<_, BitStackStruct<u64, u16>>::with_config(reader, &mut buffer);
96
    /// ```
97
    pub fn with_config(reader: R, buffer: &'b mut [u8]) -> Self {
1,077✔
98
        Self {
1,077✔
99
            tokenizer: Tokenizer::new(),
1,077✔
100
            parser_state: ParserState::new(),
1,077✔
101
            reader,
1,077✔
102
            stream_buffer: StreamBuffer::new(buffer),
1,077✔
103

1,077✔
104
            // Initialize new state machine to Active with default values
1,077✔
105
            processing_state: ProcessingState::Active {
1,077✔
106
                unescaped_reset_queued: false,
1,077✔
107
                in_escape_sequence: false,
1,077✔
108
            },
1,077✔
109

1,077✔
110
            unicode_escape_collector: UnicodeEscapeCollector::new(),
1,077✔
111
        }
1,077✔
112
    }
1,077✔
113
}
114

115
/// Shared methods for StreamParser with any BitStackConfig
116
impl<R: Reader, C: BitStackConfig> StreamParser<'_, R, C> {
117
    /// Get the next JSON event from the stream
118
    fn next_event_impl(&mut self) -> Result<Event<'_, '_>, ParseError> {
4,960✔
119
        // Apply any queued unescaped content reset from previous call
120
        self.apply_unescaped_reset_if_queued();
4,960✔
121

122
        loop {
123
            // Pull events from tokenizer until we have some
124
            while !self.have_events() {
27,266✔
125
                // Only fill buffer when we actually need more data
126
                if self.stream_buffer.is_empty() {
19,319✔
127
                    self.fill_buffer_from_reader()?;
6,896✔
128
                }
12,423✔
129

130
                if self.stream_buffer.is_empty() {
18,790✔
131
                    // Handle end of data with tokenizer finish
132
                    if !matches!(self.processing_state, ProcessingState::Finished) {
497✔
133
                        self.processing_state = ProcessingState::Finished;
493✔
134

135
                        // Clear events and try to finish tokenizer
136
                        clear_events(&mut self.parser_state.evts);
493✔
137
                        {
138
                            let mut callback =
493✔
139
                                create_tokenizer_callback(&mut self.parser_state.evts);
493✔
140
                            if let Err(e) = self.tokenizer.finish(&mut callback) {
493✔
141
                                return Err(ParseError::TokenizerError(e));
1✔
142
                            }
492✔
143
                        }
144
                    }
4✔
145

146
                    if !self.have_events() {
496✔
147
                        return Ok(Event::EndDocument);
492✔
148
                    }
4✔
149
                    // Continue to process any events generated by finish()
150
                } else {
151
                    // Get byte and advance
152
                    let byte = self.stream_buffer.current_byte()?;
18,293✔
153
                    self.stream_buffer.advance()?;
18,293✔
154

155
                    // Process byte through tokenizer
156
                    clear_events(&mut self.parser_state.evts);
18,293✔
157
                    {
158
                        let mut callback = create_tokenizer_callback(&mut self.parser_state.evts);
18,293✔
159
                        if let Err(e) = self.tokenizer.parse_chunk(&[byte], &mut callback) {
18,293✔
NEW
160
                            return Err(ParseError::TokenizerError(e));
×
161
                        }
18,293✔
162
                    }
163

164
                    // Special case processing removed - let all escape handling go through event system
165

166
                    // Handle byte accumulation if no event was generated
167
                    if !self.have_events() {
18,293✔
168
                        self.handle_byte_accumulation(byte)?;
11,231✔
169
                    }
7,062✔
170
                }
171
            }
172

173
            // Now we have events - process ONE event
174
            let taken_event = take_first_event(&mut self.parser_state.evts);
7,947✔
175

176
            if let Some(taken_event) = taken_event {
7,947✔
177
                // Process the event directly in the main loop
178
                // First, try the shared simple event processor
179
                if let Some(simple_result) = process_simple_events(taken_event.clone()) {
7,947✔
180
                    match simple_result {
3,922✔
181
                        EventResult::Complete(event) => return Ok(event),
3,033✔
182
                        EventResult::ExtractString => return self.validate_and_extract_string(),
383✔
183
                        EventResult::ExtractKey => return self.validate_and_extract_key(),
255✔
184
                        EventResult::ExtractNumber(from_container_end) => {
251✔
185
                            return self.validate_and_extract_number(from_container_end)
251✔
186
                        }
NEW
187
                        EventResult::Continue => {
×
NEW
188
                            // Continue to next iteration for more events
×
UNCOV
189
                        }
×
190
                    }
191
                } else if let Some(begin_result) = process_begin_events(&taken_event, self) {
4,025✔
192
                    match begin_result {
1,445✔
193
                        EventResult::Continue => {
1,445✔
194
                            // Continue to next iteration for more events
1,445✔
195
                        }
1,445✔
NEW
196
                        _ => unreachable!("process_begin_events only returns Continue"),
×
197
                    }
198
                } else {
199
                    // Handle parser-specific events
200
                    match taken_event {
1,018✔
201
                        // Escape sequence handling
202
                        ujson::Event::Begin(EventToken::EscapeSequence) => {
203
                            // Start of escape sequence - we'll handle escapes by unescaping to buffer
204
                            self.start_escape_processing()?;
894✔
205
                            // Continue processing
206
                        }
207
                        ujson::Event::End(
208
                            escape_token @ (EventToken::EscapeQuote
668✔
209
                            | EventToken::EscapeBackslash
210
                            | EventToken::EscapeSlash
211
                            | EventToken::EscapeBackspace
212
                            | EventToken::EscapeFormFeed
213
                            | EventToken::EscapeNewline
214
                            | EventToken::EscapeCarriageReturn
215
                            | EventToken::EscapeTab),
216
                        ) => {
217
                            // Handle simple escape sequences using shared function
218
                            process_simple_escape_event(&escape_token, self)?;
668✔
219
                            // Continue processing
220
                        }
221
                        _ if process_unicode_escape_events(&taken_event, self)? => {
1,018✔
222
                            // Unicode escape events handled by shared function
334✔
223
                            // Continue processing
334✔
224
                        }
334✔
225

226
                        // All other events - continue processing
227
                        _ => {
668✔
228
                            // Continue to next byte
668✔
229
                        }
668✔
230
                    }
231
                }
232
            }
×
233
            // If no event was processed, continue the outer loop to get more events
234
        }
235
    }
4,960✔
236

237
    /// Check if we have events waiting to be processed
238
    fn have_events(&self) -> bool {
46,055✔
239
        have_events(&self.parser_state.evts)
46,055✔
240
    }
46,055✔
241

242
    /// Helper to create an unescaped string from StreamBuffer
243
    fn create_unescaped_string(&mut self) -> Result<Event<'_, '_>, ParseError> {
176✔
244
        self.queue_unescaped_reset();
176✔
245
        let unescaped_slice = self.stream_buffer.get_unescaped_slice()?;
176✔
246
        let str_content = crate::shared::from_utf8(unescaped_slice)?;
176✔
247
        Ok(Event::String(crate::String::Unescaped(str_content)))
176✔
248
    }
176✔
249

250
    /// Helper to create a borrowed string from StreamBuffer
251
    fn create_borrowed_string(
205✔
252
        &mut self,
205✔
253
        content_start: usize,
205✔
254
    ) -> Result<Event<'_, '_>, ParseError> {
205✔
255
        let current_pos = self.stream_buffer.current_position();
205✔
256
        let (content_start, content_end) =
205✔
257
            ContentRange::string_content_bounds_from_content_start(content_start, current_pos);
205✔
258

259
        let bytes = self
205✔
260
            .stream_buffer
205✔
261
            .get_string_slice(content_start, content_end)?;
205✔
262
        let str_content = crate::shared::from_utf8(bytes)?;
205✔
263
        Ok(Event::String(crate::String::Borrowed(str_content)))
205✔
264
    }
205✔
265

266
    /// Helper to create an unescaped key from StreamBuffer
267
    fn create_unescaped_key(&mut self) -> Result<Event<'_, '_>, ParseError> {
2✔
268
        self.queue_unescaped_reset();
2✔
269
        let unescaped_slice = self.stream_buffer.get_unescaped_slice()?;
2✔
270
        let str_content = crate::shared::from_utf8(unescaped_slice)?;
2✔
271
        Ok(Event::Key(crate::String::Unescaped(str_content)))
2✔
272
    }
2✔
273

274
    /// Helper to create a borrowed key from StreamBuffer
275
    fn create_borrowed_key(&mut self, content_start: usize) -> Result<Event<'_, '_>, ParseError> {
253✔
276
        let current_pos = self.stream_buffer.current_position();
253✔
277
        let (content_start, content_end) =
253✔
278
            ContentRange::string_content_bounds_from_content_start(content_start, current_pos);
253✔
279

280
        let bytes = self
253✔
281
            .stream_buffer
253✔
282
            .get_string_slice(content_start, content_end)?;
253✔
283
        let str_content = crate::shared::from_utf8(bytes)?;
253✔
284
        Ok(Event::Key(crate::String::Borrowed(str_content)))
253✔
285
    }
253✔
286

287
    /// Fill buffer from reader
288
    fn fill_buffer_from_reader(&mut self) -> Result<(), ParseError> {
6,896✔
289
        if let Some(fill_slice) = self.stream_buffer.get_fill_slice() {
6,896✔
290
            let bytes_read = self
5,106✔
291
                .reader
5,106✔
292
                .read(fill_slice)
5,106✔
293
                .map_err(|_| ParseError::ReaderError)?;
5,106✔
294

295
            self.stream_buffer.mark_filled(bytes_read)?;
5,106✔
296
        } else {
297
            // Buffer is full - ALWAYS attempt compaction
298
            let compact_start_pos = match self.parser_state.state {
1,790✔
299
                crate::shared::State::Number(start_pos) => start_pos,
401✔
300
                crate::shared::State::Key(start_pos) => start_pos,
126✔
301
                crate::shared::State::String(start_pos) => start_pos,
702✔
302
                _ => self.stream_buffer.current_position(),
561✔
303
            };
304

305
            let offset = self.stream_buffer.compact_from(compact_start_pos)?;
1,790✔
306

307
            if offset == 0 {
1,790✔
308
                // SOL: Buffer too small for current token
309
                return Err(ParseError::ScratchBufferFull);
529✔
310
            }
1,261✔
311

312
            // Update parser state positions
313
            self.update_positions_after_compaction(offset)?;
1,261✔
314

315
            // Try to fill again after compaction
316
            if let Some(fill_slice) = self.stream_buffer.get_fill_slice() {
1,261✔
317
                let bytes_read = self
1,261✔
318
                    .reader
1,261✔
319
                    .read(fill_slice)
1,261✔
320
                    .map_err(|_| ParseError::ReaderError)?;
1,261✔
321

322
                self.stream_buffer.mark_filled(bytes_read)?;
1,261✔
323
            }
×
324
        }
325
        Ok(())
6,367✔
326
    }
6,896✔
327

328
    /// Update parser state positions after buffer compaction
329
    fn update_positions_after_compaction(&mut self, offset: usize) -> Result<(), ParseError> {
1,261✔
330
        // Check for positions that would be discarded and need escape mode
331
        // CRITICAL: Position 0 is never discarded, regardless of offset
332
        let needs_escape_mode = match &self.parser_state.state {
1,261✔
333
            crate::shared::State::Key(pos) if *pos > 0 && *pos < offset => Some((*pos, true)), // true = is_key
96✔
334
            crate::shared::State::String(pos) if *pos > 0 && *pos < offset => Some((*pos, false)), // false = is_string
395✔
335
            crate::shared::State::Number(pos) if *pos > 0 && *pos < offset => {
209✔
336
                return Err(ParseError::ScratchBufferFull);
×
337
            }
338
            _ => None,
1,261✔
339
        };
340

341
        // Handle escape mode transition if needed
342
        if let Some((original_pos, is_key)) = needs_escape_mode {
1,261✔
343
            if is_key {
×
344
                self.switch_key_to_escape_mode(original_pos, offset)?;
×
345
            } else {
346
                self.switch_string_to_escape_mode(original_pos, offset)?;
×
347
            }
348
        }
1,261✔
349

350
        // Update positions
351
        match &mut self.parser_state.state {
1,261✔
352
            crate::shared::State::None => {
561✔
353
                // No position-based state to update
561✔
354
            }
561✔
355
            crate::shared::State::Key(pos) => {
96✔
356
                if *pos > 0 && *pos < offset {
96✔
357
                    *pos = 0; // Reset for escape mode
×
358
                } else if *pos >= offset {
96✔
359
                    *pos = pos.checked_sub(offset).unwrap_or(0); // Safe position adjustment
96✔
360
                }
96✔
361
                // else: *pos == 0 or *pos < offset with pos == 0, keep as-is
362
            }
363
            crate::shared::State::String(pos) => {
395✔
364
                if *pos > 0 && *pos < offset {
395✔
365
                    *pos = 0; // Reset for escape mode
×
366
                } else if *pos >= offset {
395✔
367
                    *pos = pos.checked_sub(offset).unwrap_or(0); // Safe position adjustment
395✔
368
                }
395✔
369
                // else: *pos == 0 or *pos < offset with pos == 0, keep as-is
370
            }
371
            crate::shared::State::Number(pos) => {
209✔
372
                if *pos >= offset {
209✔
373
                    *pos = pos.checked_sub(offset).unwrap_or(0); // Safe position adjustment
209✔
374
                } else {
209✔
375
                    *pos = 0; // Reset for discarded number start
×
376
                }
×
377
            }
378
        }
379

380
        Ok(())
1,261✔
381
    }
1,261✔
382

383
    /// Switch key processing to escape/copy mode when original position was discarded
384
    fn switch_key_to_escape_mode(
×
385
        &mut self,
×
386
        original_pos: usize,
×
387
        offset: usize,
×
388
    ) -> Result<(), ParseError> {
×
389
        // The key start position was in the discarded portion of the buffer
390

391
        // For keys, the original_pos now points to the content start (after opening quote)
392
        // If offset > original_pos, it means some actual content was discarded
393

394
        // Calculate how much actual key content was discarded
395
        let content_start = original_pos; // Key content starts at original_pos (now tracks content directly)
×
396
        let discarded_content = offset.saturating_sub(content_start);
×
397

398
        if discarded_content > 0 {
×
399
            // We lost some actual key content - this would require content recovery
400
            // For now, this is unsupported
401
            return Err(ParseError::ScratchBufferFull);
×
402
        }
×
403

404
        // No actual content was discarded, we can continue parsing
405
        // We can continue parsing the key from the current position
406
        Ok(())
×
407
    }
×
408

409
    /// Switch string processing to escape/copy mode when original position was discarded
410
    fn switch_string_to_escape_mode(
×
411
        &mut self,
×
412
        original_pos: usize,
×
413
        offset: usize,
×
414
    ) -> Result<(), ParseError> {
×
415
        // The string start position was in the discarded portion of the buffer
416

417
        // For strings, the original_pos now points to the content start (after opening quote)
418
        // If offset > original_pos, it means some actual content was discarded
419

420
        // Calculate how much actual string content was discarded
421
        let content_start = original_pos; // String content starts at original_pos (now tracks content directly)
×
422
        let discarded_content = offset.saturating_sub(content_start);
×
423

424
        if discarded_content > 0 {
×
425
            // We lost some actual string content - this would require content recovery
426
            // For now, this is unsupported
427
            return Err(ParseError::ScratchBufferFull);
×
428
        }
×
429

430
        // No actual content was discarded, we can continue parsing
431
        // We can continue parsing the string from the current position
432
        Ok(())
×
433
    }
×
434

435
    /// Handle byte accumulation for strings/keys and Unicode escape sequences
436
    fn handle_byte_accumulation(&mut self, byte: u8) -> Result<(), ParseError> {
11,231✔
437
        // Check if we're in a string or key state
438
        let in_string_mode = matches!(
11,231✔
439
            self.parser_state.state,
11,231✔
440
            crate::shared::State::String(_) | crate::shared::State::Key(_)
441
        );
442

443
        if in_string_mode {
11,231✔
444
            // Access escape state from enum
445
            let in_escape = if let ProcessingState::Active {
6,438✔
446
                in_escape_sequence, ..
6,438✔
447
            } = &self.processing_state
6,438✔
448
            {
449
                *in_escape_sequence
6,438✔
450
            } else {
451
                false
×
452
            };
453

454
            // Normal byte accumulation - all escape processing now goes through event system
455
            // Skip writing bytes to escape buffer when we have a pending high surrogate
456
            // (prevents literal \uD801 text from being included in final string)
457
            if !in_escape
6,438✔
458
                && self.stream_buffer.has_unescaped_content()
5,898✔
459
                && !self.unicode_escape_collector.has_pending_high_surrogate()
394✔
460
            {
461
                self.append_byte_to_escape_buffer(byte)?;
394✔
462
            }
6,044✔
463
        }
4,793✔
464

465
        Ok(())
11,231✔
466
    }
11,231✔
467

468
    /// Start escape processing using StreamBuffer
469
    fn start_escape_processing(&mut self) -> Result<(), ParseError> {
894✔
470
        // Update escape state in enum
471
        if let ProcessingState::Active {
472
            ref mut in_escape_sequence,
894✔
473
            ..
474
        } = self.processing_state
894✔
475
        {
894✔
476
            *in_escape_sequence = true;
894✔
477
        }
894✔
478

479
        // Initialize escape processing with StreamBuffer if not already started
480
        if !self.stream_buffer.has_unescaped_content() {
894✔
481
            if let crate::shared::State::String(start_pos) | crate::shared::State::Key(start_pos) =
340✔
482
                self.parser_state.state
344✔
483
            {
484
                let current_pos = self.stream_buffer.current_position();
344✔
485

486
                // With content tracking, start_pos is the content_start
487
                let content_start = start_pos;
344✔
488
                // Content to copy ends right before the escape character
489
                let content_end = if self.unicode_escape_collector.has_pending_high_surrogate() {
344✔
490
                    // Skip copying high surrogate text when processing low surrogate
491
                    content_start
34✔
492
                } else {
493
                    ContentRange::end_position_excluding_delimiter(current_pos)
310✔
494
                };
495

496
                // Estimate max length needed for unescaping (content so far + remaining buffer)
497
                let content_len = content_end.wrapping_sub(content_start);
344✔
498
                let max_escaped_len = self
344✔
499
                    .stream_buffer
344✔
500
                    .remaining_bytes()
344✔
501
                    .checked_add(content_len)
344✔
502
                    .ok_or(ParseError::NumericOverflow)?;
344✔
503

504
                // Start unescaping with StreamBuffer and copy existing content
505
                self.stream_buffer.start_unescaping_with_copy(
344✔
506
                    max_escaped_len,
344✔
507
                    content_start,
344✔
508
                    content_end,
344✔
509
                )?;
×
510
            }
×
511
        }
550✔
512

513
        Ok(())
894✔
514
    }
894✔
515

516
    /// Append a byte to the StreamBuffer's unescaped content
517
    fn append_byte_to_escape_buffer(&mut self, byte: u8) -> Result<(), ParseError> {
1,411✔
518
        self.stream_buffer
1,411✔
519
            .append_unescaped_byte(byte)
1,411✔
520
            .map_err(|e| e.into())
1,411✔
521
    }
1,411✔
522

523
    /// Queue a reset of unescaped content for the next next_event() call
524
    fn queue_unescaped_reset(&mut self) {
178✔
525
        // Set the reset flag in the Active state
526
        if let ProcessingState::Active {
527
            ref mut unescaped_reset_queued,
178✔
528
            ..
529
        } = self.processing_state
178✔
530
        {
178✔
531
            *unescaped_reset_queued = true;
178✔
532
        }
178✔
533
    }
178✔
534

535
    /// Apply queued unescaped content reset if flag is set
536
    fn apply_unescaped_reset_if_queued(&mut self) {
4,960✔
537
        // Check the enum field first
538
        let should_reset = if let ProcessingState::Active {
4,960✔
539
            ref mut unescaped_reset_queued,
4,956✔
540
            ..
541
        } = self.processing_state
4,960✔
542
        {
543
            let needs_reset = *unescaped_reset_queued;
4,956✔
544
            *unescaped_reset_queued = false; // Clear the flag
4,956✔
545
            needs_reset
4,956✔
546
        } else {
547
            false
4✔
548
        };
549

550
        if should_reset {
4,960✔
551
            self.stream_buffer.clear_unescaped();
149✔
552
        }
4,811✔
553
    }
4,960✔
554
}
555

556
impl<'b, R: Reader, C: BitStackConfig> ParserContext for StreamParser<'b, R, C> {
557
    fn current_position(&self) -> usize {
1,434✔
558
        self.stream_buffer.current_position()
1,434✔
559
    }
1,434✔
560

561
    fn begin_string_content(&mut self, _pos: usize) {
991✔
562
        // StreamParser doesn't need explicit string begin setup like SliceParser
563
        // String processing is handled automatically by the StreamBuffer
564
    }
991✔
565

566
    fn set_parser_state(&mut self, state: crate::shared::State) {
1,434✔
567
        self.parser_state.state = state;
1,434✔
568
    }
1,434✔
569
}
570

571
impl<'b, R: Reader, C: BitStackConfig> ContentExtractor for StreamParser<'b, R, C> {
572
    fn parser_state_mut(&mut self) -> &mut crate::shared::State {
887✔
573
        &mut self.parser_state.state
887✔
574
    }
887✔
575

576
    fn extract_string_content(&mut self, start_pos: usize) -> Result<Event<'_, '_>, ParseError> {
381✔
577
        if self.stream_buffer.has_unescaped_content() {
381✔
578
            self.create_unescaped_string()
176✔
579
        } else {
580
            self.create_borrowed_string(start_pos)
205✔
581
        }
582
    }
381✔
583

584
    fn extract_key_content(&mut self, start_pos: usize) -> Result<Event<'_, '_>, ParseError> {
255✔
585
        if self.stream_buffer.has_unescaped_content() {
255✔
586
            self.create_unescaped_key()
2✔
587
        } else {
588
            self.create_borrowed_key(start_pos)
253✔
589
        }
590
    }
255✔
591

592
    fn extract_number_content(
251✔
593
        &mut self,
251✔
594
        start_pos: usize,
251✔
595
        from_container_end: bool,
251✔
596
    ) -> Result<Event<'_, '_>, ParseError> {
251✔
597
        let number_token_start = start_pos;
251✔
598

599
        // StreamParser determines correct delimiter handling:
600
        // Only exclude delimiter when NOT at document end for standalone numbers
601
        let buffer_current_pos = self.stream_buffer.current_position();
251✔
602
        let corrected_pos =
251✔
603
            if !from_container_end && matches!(self.processing_state, ProcessingState::Finished) {
251✔
604
                // End(Number) at document end - no delimiter to exclude
605
                buffer_current_pos
4✔
606
            } else {
607
                // All other cases - exclude delimiter
608
                buffer_current_pos.saturating_sub(1)
247✔
609
            };
610

611
        // Use the position-controlled API - StreamParser handles all position logic
612
        crate::number_parser::parse_number_event(
251✔
613
            &self.stream_buffer,
251✔
614
            number_token_start,
251✔
615
            corrected_pos,
251✔
616
        )
617
    }
251✔
618
}
619

620
impl<'b, R: Reader, C: BitStackConfig> EscapeHandler for StreamParser<'b, R, C> {
621
    fn parser_state(&self) -> &crate::shared::State {
1,907✔
622
        &self.parser_state.state
1,907✔
623
    }
1,907✔
624

625
    fn reset_unicode_collector_all(&mut self) {
668✔
626
        self.unicode_escape_collector.reset_all();
668✔
627
    }
668✔
628

629
    fn reset_unicode_collector(&mut self) {
184✔
630
        self.unicode_escape_collector.reset();
184✔
631
    }
184✔
632

633
    fn has_pending_high_surrogate(&self) -> bool {
638✔
634
        self.unicode_escape_collector.has_pending_high_surrogate()
638✔
635
    }
638✔
636

637
    fn process_unicode_escape_with_collector(&mut self) -> Result<(), crate::ParseError> {
166✔
638
        // Update escape state in enum - Unicode escape processing is complete
639
        if let ProcessingState::Active {
640
            ref mut in_escape_sequence,
166✔
641
            ..
642
        } = self.processing_state
166✔
643
        {
166✔
644
            *in_escape_sequence = false;
166✔
645
        }
166✔
646

647
        // Process Unicode escape sequence, making a copy of the bytes to avoid borrow conflicts
648
        let utf8_bytes_copy = {
150✔
649
            let current_pos = self.stream_buffer.current_position();
166✔
650
            let hex_slice_provider = |start, end| {
166✔
651
                self.stream_buffer
166✔
652
                    .get_string_slice(start, end)
166✔
653
                    .map_err(Into::into)
166✔
654
            };
166✔
655

656
            let mut utf8_buf = [0u8; 4];
166✔
657
            let (utf8_bytes_opt, _escape_start_pos) =
150✔
658
                crate::escape_processor::process_unicode_escape_sequence(
166✔
659
                    current_pos,
166✔
660
                    &mut self.unicode_escape_collector,
166✔
661
                    hex_slice_provider,
166✔
662
                    &mut utf8_buf,
166✔
663
                )?;
16✔
664

665
            if let Some(utf8_bytes) = utf8_bytes_opt {
150✔
666
                let mut copy = [0u8; 4];
110✔
667
                let len = utf8_bytes.len();
110✔
668
                if let Some(dest) = copy.get_mut(..len) {
110✔
669
                    dest.copy_from_slice(utf8_bytes);
110✔
670
                }
110✔
671
                (copy, len)
110✔
672
            } else {
673
                // High surrogate waiting for low surrogate - no UTF-8 bytes to process
674
                ([0u8; 4], 0)
40✔
675
            }
676
        };
677

678
        // Now append the copied bytes to avoid borrow conflicts
679
        if let Some(bytes_to_copy) = utf8_bytes_copy.0.get(..utf8_bytes_copy.1) {
150✔
680
            for &byte in bytes_to_copy {
499✔
681
                self.append_byte_to_escape_buffer(byte)?;
349✔
682
            }
683
        }
×
684

685
        Ok(())
150✔
686
    }
166✔
687

688
    fn handle_simple_escape_char(&mut self, escape_char: u8) -> Result<(), crate::ParseError> {
668✔
689
        // Update escape state in enum
690
        if let ProcessingState::Active {
691
            ref mut in_escape_sequence,
668✔
692
            ..
693
        } = self.processing_state
668✔
694
        {
668✔
695
            *in_escape_sequence = false;
668✔
696
        }
668✔
697

698
        self.append_byte_to_escape_buffer(escape_char)?;
668✔
699
        Ok(())
668✔
700
    }
668✔
701
}
702

703
impl<'b, R: Reader, C: BitStackConfig> PullParser for StreamParser<'b, R, C> {
704
    fn next_event(&mut self) -> Result<Event<'_, '_>, ParseError> {
4,960✔
705
        self.next_event_impl()
4,960✔
706
    }
4,960✔
707
}
708

709
#[cfg(test)]
710
mod tests {
711
    use super::*;
712

713
    /// Simple test reader that reads from a byte slice
714
    pub struct SliceReader<'a> {
715
        data: &'a [u8],
716
        position: usize,
717
    }
718

719
    impl<'a> SliceReader<'a> {
720
        pub fn new(data: &'a [u8]) -> Self {
39✔
721
            Self { data, position: 0 }
39✔
722
        }
39✔
723
    }
724

725
    impl Reader for SliceReader<'_> {
726
        type Error = ();
727

728
        fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
69✔
729
            let remaining = self.data.len().saturating_sub(self.position);
69✔
730
            if remaining == 0 {
69✔
731
                return Ok(0); // EOF
30✔
732
            }
39✔
733

734
            let to_copy = remaining.min(buf.len());
39✔
735
            let end_pos = self.position.saturating_add(to_copy);
39✔
736
            if let (Some(dest), Some(src)) = (
39✔
737
                buf.get_mut(..to_copy),
39✔
738
                self.data.get(self.position..end_pos),
39✔
739
            ) {
740
                dest.copy_from_slice(src);
39✔
741
                self.position = end_pos;
39✔
742
                Ok(to_copy)
39✔
743
            } else {
744
                Err(())
×
745
            }
746
        }
69✔
747
    }
748

749
    type TestStreamParser<'b> = StreamParser<'b, SliceReader<'static>>;
750

751
    #[test]
752
    fn test_direct_parser_simple_object() {
1✔
753
        let json = b"{}";
1✔
754
        let reader = SliceReader::new(json);
1✔
755
        let mut buffer = [0u8; 256];
1✔
756
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
757

758
        // Should get ObjectStart
759
        let event = parser.next_event().unwrap();
1✔
760
        assert!(matches!(event, Event::StartObject));
1✔
761

762
        // Should get ObjectEnd
763
        let event = parser.next_event().unwrap();
1✔
764
        assert!(matches!(event, Event::EndObject));
1✔
765

766
        // Should get EndDocument
767
        let event = parser.next_event().unwrap();
1✔
768
        assert!(matches!(event, Event::EndDocument));
1✔
769
    }
1✔
770

771
    #[test]
772
    fn test_direct_parser_simple_array() {
1✔
773
        let json = b"[]";
1✔
774
        let reader = SliceReader::new(json);
1✔
775
        let mut buffer = [0u8; 256];
1✔
776
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
777

778
        // Should get ArrayStart
779
        let event = parser.next_event().unwrap();
1✔
780
        assert!(matches!(event, Event::StartArray));
1✔
781

782
        // Should get ArrayEnd
783
        let event = parser.next_event().unwrap();
1✔
784
        assert!(matches!(event, Event::EndArray));
1✔
785

786
        // Should get EndDocument
787
        let event = parser.next_event().unwrap();
1✔
788
        assert!(matches!(event, Event::EndDocument));
1✔
789
    }
1✔
790

791
    #[test]
792
    fn test_direct_parser_simple_escape() {
1✔
793
        let json = b"\"hello\\nworld\"";
1✔
794
        let reader = SliceReader::new(json);
1✔
795
        let mut buffer = [0u8; 256];
1✔
796
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
797

798
        if let Event::String(json_string) = parser.next_event().unwrap() {
1✔
799
            assert_eq!(json_string.as_str(), "hello\nworld");
1✔
800
        } else {
801
            panic!("Expected String event");
×
802
        }
803
    }
1✔
804

805
    #[test]
806
    fn test_pending_state_edge_cases() {
1✔
807
        // Test 1: Complex nested container endings
808
        let json1 = br#"{"a": {"b": [{"c": 123}]}}"#;
1✔
809
        let reader1 = SliceReader::new(json1);
1✔
810
        let mut buffer1 = [0u8; 256];
1✔
811
        let mut parser1 = TestStreamParser::new(reader1, &mut buffer1);
1✔
812

813
        let mut events = Vec::new();
1✔
814
        loop {
815
            match parser1.next_event() {
13✔
816
                Ok(Event::EndDocument) => break,
1✔
817
                Ok(event) => events.push(format!("{:?}", event)),
12✔
818
                Err(e) => panic!("Nested containers failed: {:?}", e),
×
819
            }
820
        }
821

822
        // Should contain all expected events
823
        assert!(events.len() >= 8); // StartObject, Key, StartObject, Key, StartArray, StartObject, Key, Number, EndObject, EndArray, EndObject, EndObject
1✔
824

825
        // Test 2: Mixed types after numbers in array
826
        let json2 = br#"[123, "string", true, null, 456]"#;
1✔
827
        let reader2 = SliceReader::new(json2);
1✔
828
        let mut buffer2 = [0u8; 256];
1✔
829
        let mut parser2 = TestStreamParser::new(reader2, &mut buffer2);
1✔
830

831
        let mut number_count = 0;
1✔
832
        loop {
833
            match parser2.next_event() {
8✔
834
                Ok(Event::EndDocument) => break,
1✔
835
                Ok(Event::Number(_)) => number_count += 1,
2✔
836
                Ok(_) => {}
5✔
837
                Err(e) => panic!("Mixed types failed: {:?}", e),
×
838
            }
839
        }
840
        assert_eq!(number_count, 2); // Should find both 123 and 456
1✔
841

842
        // Test 3: Empty containers
843
        let json3 = br#"[[], {}, [{}], {"empty": []}]"#;
1✔
844
        let reader3 = SliceReader::new(json3);
1✔
845
        let mut buffer3 = [0u8; 256];
1✔
846
        let mut parser3 = TestStreamParser::new(reader3, &mut buffer3);
1✔
847

848
        loop {
849
            match parser3.next_event() {
16✔
850
                Ok(Event::EndDocument) => break,
1✔
851
                Ok(_) => {}
15✔
852
                Err(e) => panic!("Empty containers failed: {:?}", e),
×
853
            }
854
        }
855

856
        // Test 4: Multiple consecutive numbers
857
        let json4 = br#"[1, 2, 3, 4, 5]"#;
1✔
858
        let reader4 = SliceReader::new(json4);
1✔
859
        let mut buffer4 = [0u8; 256];
1✔
860
        let mut parser4 = TestStreamParser::new(reader4, &mut buffer4);
1✔
861

862
        let mut consecutive_numbers = Vec::new();
1✔
863
        loop {
864
            match parser4.next_event() {
8✔
865
                Ok(Event::EndDocument) => break,
1✔
866
                Ok(Event::Number(n)) => consecutive_numbers.push(n.as_str().to_string()),
5✔
867
                Ok(_) => {}
2✔
868
                Err(e) => panic!("Consecutive numbers failed: {:?}", e),
×
869
            }
870
        }
871
        assert_eq!(consecutive_numbers, vec!["1", "2", "3", "4", "5"]);
1✔
872
    }
1✔
873

874
    #[test]
875
    fn test_error_recovery_with_pending_state() {
1✔
876
        // Test error handling - this should fail gracefully without hanging onto pending state
877
        let invalid_json = br#"{"key": 123,"#; // Missing closing brace
1✔
878
        let reader = SliceReader::new(invalid_json);
1✔
879
        let mut buffer = [0u8; 256];
1✔
880
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
881

882
        // Parse until we hit an error or EOF
883
        loop {
884
            match parser.next_event() {
4✔
885
                Ok(Event::EndDocument) => break, // EOF reached
×
886
                Ok(_) => {}
3✔
887
                Err(_) => break, // Error occurred - this is expected
1✔
888
            }
889
        }
890

891
        // The important thing is that we don't panic or hang
892
        // The specific error behavior may vary
893
    }
1✔
894

895
    #[test]
896
    fn test_multiple_rapid_container_ends() {
1✔
897
        // Test deeply nested structures that end with numbers
898
        // This tests whether we can handle multiple rapid container ends correctly
899

900
        // Test 1: Deeply nested arrays ending with number
901
        let json1 = br#"[[[123]]]"#;
1✔
902
        let reader1 = SliceReader::new(json1);
1✔
903
        let mut buffer1 = [0u8; 256];
1✔
904
        let mut parser1 = TestStreamParser::new(reader1, &mut buffer1);
1✔
905

906
        let mut events1 = Vec::new();
1✔
907
        loop {
908
            match parser1.next_event() {
8✔
909
                Ok(Event::EndDocument) => break,
1✔
910
                Ok(event) => events1.push(format!("{:?}", event)),
7✔
911
                Err(e) => panic!("Deeply nested arrays failed: {:?}", e),
×
912
            }
913
        }
914

915
        // Should have: StartArray, StartArray, StartArray, Number(123), EndArray, EndArray, EndArray
916
        assert_eq!(events1.len(), 7);
1✔
917
        assert!(events1[3].contains("Number"));
1✔
918
        assert_eq!(&events1[4], "EndArray");
1✔
919
        assert_eq!(&events1[5], "EndArray");
1✔
920
        assert_eq!(&events1[6], "EndArray");
1✔
921

922
        // Test 2: Mixed nested containers ending with number
923
        let json2 = br#"{"a": [{"b": 456}]}"#;
1✔
924
        let reader2 = SliceReader::new(json2);
1✔
925
        let mut buffer2 = [0u8; 256];
1✔
926
        let mut parser2 = TestStreamParser::new(reader2, &mut buffer2);
1✔
927

928
        let mut events2 = Vec::new();
1✔
929
        loop {
930
            match parser2.next_event() {
10✔
931
                Ok(Event::EndDocument) => break,
1✔
932
                Ok(event) => events2.push(format!("{:?}", event)),
9✔
933
                Err(e) => panic!("Mixed nested containers failed: {:?}", e),
×
934
            }
935
        }
936

937
        // Should properly handle the sequence of: number -> EndObject -> EndArray -> EndObject
938
        assert!(events2.len() >= 8);
1✔
939

940
        // Test 3: Multiple numbers at different nesting levels
941
        let json3 = br#"[123, [456, [789]]]"#;
1✔
942
        let reader3 = SliceReader::new(json3);
1✔
943
        let mut buffer3 = [0u8; 256];
1✔
944
        let mut parser3 = TestStreamParser::new(reader3, &mut buffer3);
1✔
945

946
        let mut number_count = 0;
1✔
947
        let mut events3 = Vec::new();
1✔
948
        loop {
949
            match parser3.next_event() {
10✔
950
                Ok(Event::EndDocument) => break,
1✔
951
                Ok(Event::Number(n)) => {
3✔
952
                    number_count += 1;
3✔
953
                    events3.push(format!("Number({})", n.as_str()));
3✔
954
                }
3✔
955
                Ok(event) => events3.push(format!("{:?}", event)),
6✔
956
                Err(e) => panic!("Multiple nested numbers failed: {:?}", e),
×
957
            }
958
        }
959

960
        assert_eq!(number_count, 3); // Should find all three numbers: 123, 456, 789
1✔
961
    }
1✔
962

963
    #[test]
964
    fn test_pending_flag_priority() {
1✔
965
        // Defensive test: ensure that if both pending flags were somehow set,
966
        // we handle it gracefully (this shouldn't happen in normal operation)
967

968
        let json = br#"[{"key": 123}]"#;
1✔
969
        let reader = SliceReader::new(json);
1✔
970
        let mut buffer = [0u8; 256];
1✔
971
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
972

973
        // Parse normally - this should work fine and never set both flags
974
        let mut events = Vec::new();
1✔
975
        loop {
976
            match parser.next_event() {
7✔
977
                Ok(Event::EndDocument) => break,
1✔
978
                Ok(event) => events.push(format!("{:?}", event)),
6✔
979
                Err(e) => panic!("Flag priority test failed: {:?}", e),
×
980
            }
981
        }
982

983
        // Should successfully parse: StartArray, StartObject, Key, Number, EndObject, EndArray
984
        assert_eq!(events.len(), 6);
1✔
985
        assert!(events[3].contains("Number"));
1✔
986
        assert_eq!(&events[4], "EndObject");
1✔
987
        assert_eq!(&events[5], "EndArray");
1✔
988
    }
1✔
989

990
    #[test]
991
    fn test_direct_parser_array_of_strings() {
1✔
992
        let json = b"[\"first\", \"second\"]";
1✔
993
        let reader = SliceReader::new(json);
1✔
994
        let mut buffer = [0u8; 256];
1✔
995
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
996

997
        assert!(matches!(parser.next_event().unwrap(), Event::StartArray));
1✔
998

999
        if let Event::String(s1) = parser.next_event().unwrap() {
1✔
1000
            assert_eq!(s1.as_str(), "first");
1✔
1001
        } else {
1002
            panic!("Expected String event");
×
1003
        }
1004

1005
        if let Event::String(s2) = parser.next_event().unwrap() {
1✔
1006
            assert_eq!(s2.as_str(), "second");
1✔
1007
        } else {
1008
            panic!("Expected String event");
×
1009
        }
1010

1011
        assert!(matches!(parser.next_event().unwrap(), Event::EndArray));
1✔
1012
    }
1✔
1013

1014
    #[test]
1015
    fn test_direct_parser_object_with_keys() {
1✔
1016
        let json = b"{\"name\": \"value\", \"count\": \"42\"}";
1✔
1017
        let reader = SliceReader::new(json);
1✔
1018
        let mut buffer = [0u8; 256];
1✔
1019
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1020

1021
        assert!(matches!(parser.next_event().unwrap(), Event::StartObject));
1✔
1022

1023
        // First key-value pair
1024
        if let Event::Key(key1) = parser.next_event().unwrap() {
1✔
1025
            assert_eq!(key1.as_str(), "name");
1✔
1026
        } else {
1027
            panic!("Expected Key event");
×
1028
        }
1029

1030
        if let Event::String(val1) = parser.next_event().unwrap() {
1✔
1031
            assert_eq!(val1.as_str(), "value");
1✔
1032
        } else {
1033
            panic!("Expected String event");
×
1034
        }
1035

1036
        // Second key-value pair
1037
        if let Event::Key(key2) = parser.next_event().unwrap() {
1✔
1038
            assert_eq!(key2.as_str(), "count");
1✔
1039
        } else {
1040
            panic!("Expected Key event");
×
1041
        }
1042

1043
        if let Event::String(val2) = parser.next_event().unwrap() {
1✔
1044
            assert_eq!(val2.as_str(), "42");
1✔
1045
        } else {
1046
            panic!("Expected String event");
×
1047
        }
1048

1049
        assert!(matches!(parser.next_event().unwrap(), Event::EndObject));
1✔
1050
    }
1✔
1051

1052
    #[test]
1053
    fn test_direct_parser_multiple_escapes() {
1✔
1054
        let json = b"\"line1\\nline2\\ttab\\\"quote\"";
1✔
1055
        let reader = SliceReader::new(json);
1✔
1056
        let mut buffer = [0u8; 256];
1✔
1057
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1058

1059
        if let Event::String(json_string) = parser.next_event().unwrap() {
1✔
1060
            let content = json_string.as_str();
1✔
1061
            // Check that escape sequences were properly processed
1062
            let has_newline = content.contains('\n');
1✔
1063
            let has_tab = content.contains('\t');
1✔
1064
            let has_quote = content.contains('"');
1✔
1065

1066
            // These should be real control characters, not literal \n \t \"
1067
            assert!(has_newline, "Should contain actual newline character");
1✔
1068
            assert!(has_tab, "Should contain actual tab character");
1✔
1069
            assert!(has_quote, "Should contain actual quote character");
1✔
1070
        } else {
1071
            panic!("Expected String event");
×
1072
        }
1073
    }
1✔
1074

1075
    #[test]
1076
    fn test_direct_parser_unicode_escape() {
1✔
1077
        let json = b"\"Hello \\u0041\\u03B1\""; // Hello A(alpha)
1✔
1078
        let reader = SliceReader::new(json);
1✔
1079
        let mut buffer = [0u8; 256];
1✔
1080
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1081

1082
        if let Event::String(json_string) = parser.next_event().unwrap() {
1✔
1083
            let content = json_string.as_str();
1✔
1084
            // Should be "Hello A⍺" (with actual A and alpha characters)
1085
            assert!(content.contains('A'));
1✔
1086
            // Note: This test will initially fail until we implement Unicode escapes
1087
        } else {
1088
            panic!("Expected String event");
×
1089
        }
1090
    }
1✔
1091

1092
    #[test]
1093
    fn test_direct_parser_boolean_true() {
1✔
1094
        let json = b"true";
1✔
1095
        let reader = SliceReader::new(json);
1✔
1096
        let mut buffer = [0u8; 256];
1✔
1097
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1098

1099
        let event = parser.next_event().unwrap();
1✔
1100
        assert_eq!(event, Event::Bool(true));
1✔
1101

1102
        let event = parser.next_event().unwrap();
1✔
1103
        assert_eq!(event, Event::EndDocument);
1✔
1104
    }
1✔
1105

1106
    #[test]
1107
    fn test_direct_parser_boolean_false() {
1✔
1108
        let json = b"false";
1✔
1109
        let reader = SliceReader::new(json);
1✔
1110
        let mut buffer = [0u8; 256];
1✔
1111
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1112

1113
        let event = parser.next_event().unwrap();
1✔
1114
        assert_eq!(event, Event::Bool(false));
1✔
1115

1116
        let event = parser.next_event().unwrap();
1✔
1117
        assert_eq!(event, Event::EndDocument);
1✔
1118
    }
1✔
1119

1120
    #[test]
1121
    fn test_direct_parser_null() {
1✔
1122
        let json = b"null";
1✔
1123
        let reader = SliceReader::new(json);
1✔
1124
        let mut buffer = [0u8; 256];
1✔
1125
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1126

1127
        let event = parser.next_event().unwrap();
1✔
1128
        assert_eq!(event, Event::Null);
1✔
1129

1130
        let event = parser.next_event().unwrap();
1✔
1131
        assert_eq!(event, Event::EndDocument);
1✔
1132
    }
1✔
1133

1134
    #[test]
1135
    fn test_direct_parser_booleans_in_array() {
1✔
1136
        let json = b"[true, false, null]";
1✔
1137
        let reader = SliceReader::new(json);
1✔
1138
        let mut buffer = [0u8; 256];
1✔
1139
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1140

1141
        assert_eq!(parser.next_event().unwrap(), Event::StartArray);
1✔
1142
        assert_eq!(parser.next_event().unwrap(), Event::Bool(true));
1✔
1143
        assert_eq!(parser.next_event().unwrap(), Event::Bool(false));
1✔
1144
        assert_eq!(parser.next_event().unwrap(), Event::Null);
1✔
1145
        assert_eq!(parser.next_event().unwrap(), Event::EndArray);
1✔
1146
        assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1147
    }
1✔
1148

1149
    #[test]
1150
    fn test_direct_parser_number_simple() {
1✔
1151
        let json = b"42";
1✔
1152
        let reader = SliceReader::new(json);
1✔
1153
        let mut buffer = [0u8; 256];
1✔
1154
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1155

1156
        let event = parser.next_event().unwrap();
1✔
1157
        if let Event::Number(json_number) = event {
1✔
1158
            assert_eq!(json_number.as_str(), "42");
1✔
1159
        } else {
1160
            panic!("Expected Number event, got: {:?}", event);
×
1161
        }
1162

1163
        let event = parser.next_event().unwrap();
1✔
1164
        assert_eq!(event, Event::EndDocument);
1✔
1165
    }
1✔
1166

1167
    #[test]
1168
    fn test_direct_parser_number_negative() {
1✔
1169
        let json = b"-123";
1✔
1170
        let reader = SliceReader::new(json);
1✔
1171
        let mut buffer = [0u8; 256];
1✔
1172
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1173

1174
        let event = parser.next_event().unwrap();
1✔
1175
        if let Event::Number(json_number) = event {
1✔
1176
            assert_eq!(json_number.as_str(), "-123");
1✔
1177
        } else {
1178
            panic!("Expected Number event, got: {:?}", event);
×
1179
        }
1180

1181
        let event = parser.next_event().unwrap();
1✔
1182
        assert_eq!(event, Event::EndDocument);
1✔
1183
    }
1✔
1184

1185
    #[test]
1186
    fn test_direct_parser_number_float() {
1✔
1187
        let json = b"3.14159";
1✔
1188
        let reader = SliceReader::new(json);
1✔
1189
        let mut buffer = [0u8; 256];
1✔
1190
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1191

1192
        #[cfg(feature = "float-error")]
1193
        {
1194
            // float-error configuration should return an error for float values
1195
            let result = parser.next_event();
1196
            assert!(
1197
                result.is_err(),
1198
                "Expected error for float with float-error configuration"
1199
            );
1200
            return;
1201
        }
1202

1203
        #[cfg(not(feature = "float-error"))]
1204
        {
1205
            let event = parser.next_event().unwrap();
1✔
1206
            if let Event::Number(json_number) = event {
1✔
1207
                assert_eq!(json_number.as_str(), "3.14159");
1✔
1208
            } else {
1209
                panic!("Expected Number event, got: {:?}", event);
×
1210
            }
1211

1212
            let event = parser.next_event().unwrap();
1✔
1213
            assert_eq!(event, Event::EndDocument);
1✔
1214
        }
1215
    }
1✔
1216

1217
    #[test]
1218
    fn test_direct_parser_numbers_in_array() {
1✔
1219
        #[cfg(feature = "float-error")]
1220
        let json = b"[42, -7]"; // No floats for float-error config
1221
        #[cfg(not(feature = "float-error"))]
1222
        let json = b"[42, -7, 3.14]"; // Include float for other configs
1✔
1223

1224
        let reader = SliceReader::new(json);
1✔
1225
        let mut buffer = [0u8; 256];
1✔
1226
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1227

1228
        assert_eq!(parser.next_event().unwrap(), Event::StartArray);
1✔
1229

1230
        let event = parser.next_event().unwrap();
1✔
1231
        if let Event::Number(json_number) = event {
1✔
1232
            assert_eq!(json_number.as_str(), "42");
1✔
1233
        } else {
1234
            panic!("Expected Number event, got: {:?}", event);
×
1235
        }
1236

1237
        let event = parser.next_event().unwrap();
1✔
1238
        if let Event::Number(json_number) = event {
1✔
1239
            assert_eq!(json_number.as_str(), "-7");
1✔
1240
        } else {
1241
            panic!("Expected Number event, got: {:?}", event);
×
1242
        }
1243

1244
        #[cfg(not(feature = "float-error"))]
1245
        {
1246
            let event = parser.next_event().unwrap();
1✔
1247
            if let Event::Number(json_number) = event {
1✔
1248
                assert_eq!(json_number.as_str(), "3.14");
1✔
1249
            } else {
1250
                panic!("Expected Number event, got: {:?}", event);
×
1251
            }
1252
        }
1253

1254
        assert_eq!(parser.next_event().unwrap(), Event::EndArray);
1✔
1255
        assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1256
    }
1✔
1257

1258
    #[test]
1259
    fn test_direct_parser_numbers_in_object() {
1✔
1260
        #[cfg(feature = "float-error")]
1261
        let json = b"{\"count\": 42, \"score\": -7}"; // No floats for float-error config
1262
        #[cfg(not(feature = "float-error"))]
1263
        let json = b"{\"count\": 42, \"score\": -7.5}"; // Include float for other configs
1✔
1264

1265
        let reader = SliceReader::new(json);
1✔
1266
        let mut buffer = [0u8; 256];
1✔
1267
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1268

1269
        assert_eq!(parser.next_event().unwrap(), Event::StartObject);
1✔
1270

1271
        // First key-value pair
1272
        if let Event::Key(key1) = parser.next_event().unwrap() {
1✔
1273
            assert_eq!(key1.as_str(), "count");
1✔
1274
        } else {
1275
            panic!("Expected Key event");
×
1276
        }
1277

1278
        if let Event::Number(val1) = parser.next_event().unwrap() {
1✔
1279
            assert_eq!(val1.as_str(), "42");
1✔
1280
        } else {
1281
            panic!("Expected Number event");
×
1282
        }
1283

1284
        // Second key-value pair
1285
        if let Event::Key(key2) = parser.next_event().unwrap() {
1✔
1286
            assert_eq!(key2.as_str(), "score");
1✔
1287
        } else {
1288
            panic!("Expected Key event");
×
1289
        }
1290

1291
        if let Event::Number(val2) = parser.next_event().unwrap() {
1✔
1292
            #[cfg(feature = "float-error")]
1293
            assert_eq!(val2.as_str(), "-7");
1294
            #[cfg(not(feature = "float-error"))]
1295
            assert_eq!(val2.as_str(), "-7.5");
1✔
1296
        } else {
1297
            panic!("Expected Number event");
×
1298
        }
1299

1300
        assert_eq!(parser.next_event().unwrap(), Event::EndObject);
1✔
1301
        assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1302
    }
1✔
1303

1304
    #[test]
1305
    fn test_direct_parser_no_float_configuration() {
1✔
1306
        // Test that StreamParser properly uses unified number parsing with no-float config
1307
        let json = br#"{"integer": 42, "float": 3.14, "scientific": 1e3}"#;
1✔
1308
        let reader = SliceReader::new(json);
1✔
1309
        let mut buffer = [0u8; 256];
1✔
1310
        let mut parser = TestStreamParser::new(reader, &mut buffer);
1✔
1311

1312
        // Parse through the JSON and verify number handling
1313
        assert_eq!(parser.next_event().unwrap(), Event::StartObject);
1✔
1314

1315
        // Integer key-value
1316
        assert_eq!(
1✔
1317
            parser.next_event().unwrap(),
1✔
1318
            Event::Key(crate::String::Borrowed("integer"))
1319
        );
1320
        if let Event::Number(num) = parser.next_event().unwrap() {
1✔
1321
            assert_eq!(num.as_str(), "42");
1✔
1322
            match num.parsed() {
1✔
1323
                crate::NumberResult::Integer(i) => assert_eq!(*i, 42),
1✔
1324
                _ => panic!("Expected integer parsing"),
×
1325
            }
1326
        } else {
1327
            panic!("Expected Number event");
×
1328
        }
1329

1330
        // Float key-value - behavior varies by configuration
1331
        assert_eq!(
1✔
1332
            parser.next_event().unwrap(),
1✔
1333
            Event::Key(crate::String::Borrowed("float"))
1334
        );
1335

1336
        #[cfg(feature = "float-error")]
1337
        {
1338
            // float-error should return an error when encountering floats
1339
            let result = parser.next_event();
1340
            assert!(
1341
                result.is_err(),
1342
                "Expected error for float with float-error configuration"
1343
            );
1344
            // Test ends here for float-error - no more processing needed
1345
        }
1346

1347
        #[cfg(not(feature = "float-error"))]
1348
        {
1349
            if let Event::Number(num) = parser.next_event().unwrap() {
1✔
1350
                assert_eq!(num.as_str(), "3.14");
1✔
1351
                // In no-float configuration, this should be FloatDisabled
1352
                match num.parsed() {
1✔
1353
                    #[cfg(not(feature = "float"))]
1354
                    crate::NumberResult::FloatDisabled => {
1355
                        // This is expected in no-float build
1356
                    }
1357
                    #[cfg(feature = "float")]
1358
                    crate::NumberResult::Float(f) => {
1✔
1359
                        // This is expected in float-enabled build
1360
                        assert!((f - 3.14).abs() < 0.01);
1✔
1361
                    }
1362
                    #[cfg(feature = "float-skip")]
1363
                    crate::NumberResult::FloatSkipped => {
1364
                        // This is expected in float-skip build
1365
                    }
1366
                    #[cfg(feature = "float-truncate")]
1367
                    crate::NumberResult::FloatTruncated(i) => {
1368
                        // This is expected in float-truncate build (3.14 -> 3)
1369
                        assert_eq!(*i, 3);
1370
                    }
1371
                    _ => panic!("Unexpected number parsing result for float"),
×
1372
                }
1373
            } else {
1374
                panic!("Expected Number event");
×
1375
            }
1376

1377
            // Scientific notation handling varies by float configuration
1378
            assert_eq!(
1✔
1379
                parser.next_event().unwrap(),
1✔
1380
                Event::Key(crate::String::Borrowed("scientific"))
1381
            );
1382

1383
            // float-truncate rejects scientific notation, so test should end early for that config
1384
            #[cfg(feature = "float-truncate")]
1385
            {
1386
                // float-truncate rejects scientific notation since it would require float math
1387
                let result = parser.next_event();
1388
                assert!(
1389
                    result.is_err(),
1390
                    "Expected error for scientific notation with float-truncate"
1391
                );
1392
                // Test ends here for float-truncate - no more processing needed
1393
            }
1394

1395
            #[cfg(not(feature = "float-truncate"))]
1396
            {
1397
                if let Event::Number(num) = parser.next_event().unwrap() {
1✔
1398
                    assert_eq!(num.as_str(), "1e3");
1✔
1399
                    match num.parsed() {
1✔
1400
                        #[cfg(not(feature = "float"))]
1401
                        crate::NumberResult::FloatDisabled => {
1402
                            // This is expected in no-float build - raw string preserved for manual parsing
1403
                        }
1404
                        #[cfg(feature = "float-skip")]
1405
                        crate::NumberResult::FloatSkipped => {
1406
                            // This is expected in float-skip build
1407
                        }
1408
                        #[cfg(feature = "float")]
1409
                        crate::NumberResult::Float(f) => {
1✔
1410
                            // This is expected in float-enabled build
1411
                            assert!((f - 1000.0).abs() < f64::EPSILON);
1✔
1412
                        }
1413
                        _ => panic!("Unexpected number parsing result for scientific notation"),
×
1414
                    }
1415
                } else {
1416
                    panic!("Expected Number event");
×
1417
                }
1418

1419
                assert_eq!(parser.next_event().unwrap(), Event::EndObject);
1✔
1420
                assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1421
            }
1422
        }
1423
    }
1✔
1424

1425
    #[test]
1426
    fn test_number_parsing_delimiter_exclusion() {
1✔
1427
        // Test that numbers don't include trailing delimiters in various contexts
1428

1429
        // Test 1: Number followed by array end
1430
        let json1 = b"[123]";
1✔
1431
        let reader1 = SliceReader::new(json1);
1✔
1432
        let mut buffer1 = [0u8; 256];
1✔
1433
        let mut parser1 = TestStreamParser::new(reader1, &mut buffer1);
1✔
1434

1435
        assert!(matches!(parser1.next_event().unwrap(), Event::StartArray));
1✔
1436
        if let Event::Number(num) = parser1.next_event().unwrap() {
1✔
1437
            assert_eq!(
1✔
1438
                num.as_str(),
1✔
1439
                "123",
1440
                "Number should not include trailing delimiter ']'"
×
1441
            );
1442
        } else {
1443
            panic!("Expected Number event");
×
1444
        }
1445
        assert!(matches!(parser1.next_event().unwrap(), Event::EndArray));
1✔
1446

1447
        // Test 2: Number followed by object end
1448
        let json2 = b"{\"key\":456}";
1✔
1449
        let reader2 = SliceReader::new(json2);
1✔
1450
        let mut buffer2 = [0u8; 256];
1✔
1451
        let mut parser2 = TestStreamParser::new(reader2, &mut buffer2);
1✔
1452

1453
        assert!(matches!(parser2.next_event().unwrap(), Event::StartObject));
1✔
1454
        assert!(matches!(parser2.next_event().unwrap(), Event::Key(_)));
1✔
1455
        if let Event::Number(num) = parser2.next_event().unwrap() {
1✔
1456
            assert_eq!(
1✔
1457
                num.as_str(),
1✔
1458
                "456",
1459
                "Number should not include trailing delimiter '}}'"
×
1460
            );
1461
        } else {
1462
            panic!("Expected Number event");
×
1463
        }
1464
        assert!(matches!(parser2.next_event().unwrap(), Event::EndObject));
1✔
1465

1466
        // Test 3: Number followed by comma in array
1467
        let json3 = b"[789,10]";
1✔
1468
        let reader3 = SliceReader::new(json3);
1✔
1469
        let mut buffer3 = [0u8; 256];
1✔
1470
        let mut parser3 = TestStreamParser::new(reader3, &mut buffer3);
1✔
1471

1472
        assert!(matches!(parser3.next_event().unwrap(), Event::StartArray));
1✔
1473
        if let Event::Number(num1) = parser3.next_event().unwrap() {
1✔
1474
            assert_eq!(
1✔
1475
                num1.as_str(),
1✔
1476
                "789",
1477
                "First number should not include trailing delimiter ','"
×
1478
            );
1479
        } else {
1480
            panic!("Expected first Number event");
×
1481
        }
1482
        if let Event::Number(num2) = parser3.next_event().unwrap() {
1✔
1483
            assert_eq!(
1✔
1484
                num2.as_str(),
1✔
1485
                "10",
1486
                "Second number should not include trailing delimiter ']'"
×
1487
            );
1488
        } else {
1489
            panic!("Expected second Number event");
×
1490
        }
1491
        assert!(matches!(parser3.next_event().unwrap(), Event::EndArray));
1✔
1492

1493
        // Test 4: Number followed by comma in object
1494
        let json4 = b"{\"a\":11,\"b\":22}";
1✔
1495
        let reader4 = SliceReader::new(json4);
1✔
1496
        let mut buffer4 = [0u8; 256];
1✔
1497
        let mut parser4 = TestStreamParser::new(reader4, &mut buffer4);
1✔
1498

1499
        assert!(matches!(parser4.next_event().unwrap(), Event::StartObject));
1✔
1500
        assert!(matches!(parser4.next_event().unwrap(), Event::Key(_)));
1✔
1501
        if let Event::Number(num1) = parser4.next_event().unwrap() {
1✔
1502
            assert_eq!(
1✔
1503
                num1.as_str(),
1✔
1504
                "11",
1505
                "First number should not include trailing delimiter ','"
×
1506
            );
1507
        } else {
1508
            panic!("Expected first Number event");
×
1509
        }
1510
        assert!(matches!(parser4.next_event().unwrap(), Event::Key(_)));
1✔
1511
        if let Event::Number(num2) = parser4.next_event().unwrap() {
1✔
1512
            assert_eq!(
1✔
1513
                num2.as_str(),
1✔
1514
                "22",
1515
                "Second number should not include trailing delimiter '}}'"
×
1516
            );
1517
        } else {
1518
            panic!("Expected second Number event");
×
1519
        }
1520
        assert!(matches!(parser4.next_event().unwrap(), Event::EndObject));
1✔
1521

1522
        // Test 5: Standalone number at end of document (should include full content)
1523
        let json5 = b"999";
1✔
1524
        let reader5 = SliceReader::new(json5);
1✔
1525
        let mut buffer5 = [0u8; 256];
1✔
1526
        let mut parser5 = TestStreamParser::new(reader5, &mut buffer5);
1✔
1527

1528
        if let Event::Number(num) = parser5.next_event().unwrap() {
1✔
1529
            assert_eq!(
1✔
1530
                num.as_str(),
1✔
1531
                "999",
1532
                "Standalone number should include full content"
×
1533
            );
1534
        } else {
1535
            panic!("Expected Number event");
×
1536
        }
1537
        assert!(matches!(parser5.next_event().unwrap(), Event::EndDocument));
1✔
1538

1539
        // Test 6: Negative numbers with delimiters
1540
        let json6 = b"[-42,33]";
1✔
1541
        let reader6 = SliceReader::new(json6);
1✔
1542
        let mut buffer6 = [0u8; 256];
1✔
1543
        let mut parser6 = TestStreamParser::new(reader6, &mut buffer6);
1✔
1544

1545
        assert!(matches!(parser6.next_event().unwrap(), Event::StartArray));
1✔
1546
        if let Event::Number(num1) = parser6.next_event().unwrap() {
1✔
1547
            assert_eq!(
1✔
1548
                num1.as_str(),
1✔
1549
                "-42",
1550
                "Negative number should not include trailing delimiter ','"
×
1551
            );
1552
        } else {
1553
            panic!("Expected first Number event");
×
1554
        }
1555
        if let Event::Number(num2) = parser6.next_event().unwrap() {
1✔
1556
            assert_eq!(
1✔
1557
                num2.as_str(),
1✔
1558
                "33",
1559
                "Second number should not include trailing delimiter ']'"
×
1560
            );
1561
        } else {
1562
            panic!("Expected second Number event");
×
1563
        }
1564
        assert!(matches!(parser6.next_event().unwrap(), Event::EndArray));
1✔
1565

1566
        // Test 7: Decimal numbers with delimiters (if float enabled)
1567
        #[cfg(not(feature = "float-error"))]
1568
        {
1569
            let json7 = b"[3.14,2.71]";
1✔
1570
            let reader7 = SliceReader::new(json7);
1✔
1571
            let mut buffer7 = [0u8; 256];
1✔
1572
            let mut parser7 = TestStreamParser::new(reader7, &mut buffer7);
1✔
1573

1574
            assert!(matches!(parser7.next_event().unwrap(), Event::StartArray));
1✔
1575
            if let Event::Number(num1) = parser7.next_event().unwrap() {
1✔
1576
                assert_eq!(
1✔
1577
                    num1.as_str(),
1✔
1578
                    "3.14",
1579
                    "Decimal number should not include trailing delimiter ','"
×
1580
                );
1581
            } else {
1582
                panic!("Expected first Number event");
×
1583
            }
1584
            if let Event::Number(num2) = parser7.next_event().unwrap() {
1✔
1585
                assert_eq!(
1✔
1586
                    num2.as_str(),
1✔
1587
                    "2.71",
1588
                    "Second decimal number should not include trailing delimiter ']'"
×
1589
                );
1590
            } else {
1591
                panic!("Expected second Number event");
×
1592
            }
1593
            assert!(matches!(parser7.next_event().unwrap(), Event::EndArray));
1✔
1594
        }
1595
    }
1✔
1596

1597
    #[test]
1598
    fn test_escape_buffer_functions() {
1✔
1599
        // Test the uncovered escape processing functions
1600
        let json_stream = br#"{"escaped": "test\nstring"}"#;
1✔
1601
        let mut buffer = [0u8; 1024];
1✔
1602
        let mut parser = StreamParser::new(SliceReader::new(json_stream), &mut buffer);
1✔
1603

1604
        // These functions are private but we can test them through the public API
1605
        // The escape processing should trigger the uncovered functions
1606
        assert_eq!(parser.next_event().unwrap(), Event::StartObject);
1✔
1607
        assert_eq!(
1✔
1608
            parser.next_event().unwrap(),
1✔
1609
            Event::Key(crate::String::Borrowed("escaped"))
1610
        );
1611

1612
        // This should trigger append_byte_to_escape_buffer and queue_unescaped_reset
1613
        if let Event::String(s) = parser.next_event().unwrap() {
1✔
1614
            assert_eq!(s.as_ref(), "test\nstring"); // Escape sequence should be processed
1✔
1615
        } else {
1616
            panic!("Expected String event with escape sequence");
×
1617
        }
1618

1619
        assert_eq!(parser.next_event().unwrap(), Event::EndObject);
1✔
1620
        assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1621
    }
1✔
1622

1623
    #[test]
1624
    fn test_slice_reader_constructor() {
1✔
1625
        // Test the uncovered SliceReader::new function
1626
        let data = b"test data";
1✔
1627
        let reader = SliceReader::new(data);
1✔
1628
        assert_eq!(reader.data, data);
1✔
1629
        assert_eq!(reader.position, 0);
1✔
1630
    }
1✔
1631

1632
    #[test]
1633
    fn test_complex_escape_sequences() {
1✔
1634
        // Test more complex escape processing to cover the escape buffer functions
1635
        let json_stream = br#"{"multi": "line1\nline2\ttab\r\n"}"#;
1✔
1636
        let mut buffer = [0u8; 1024];
1✔
1637
        let mut parser = StreamParser::new(SliceReader::new(json_stream), &mut buffer);
1✔
1638

1639
        assert_eq!(parser.next_event().unwrap(), Event::StartObject);
1✔
1640
        assert_eq!(
1✔
1641
            parser.next_event().unwrap(),
1✔
1642
            Event::Key(crate::String::Borrowed("multi"))
1643
        );
1644

1645
        // This should exercise the escape buffer processing extensively
1646
        if let Event::String(s) = parser.next_event().unwrap() {
1✔
1647
            assert_eq!(s.as_ref(), "line1\nline2\ttab\r\n");
1✔
1648
        } else {
1649
            panic!("Expected String event");
×
1650
        }
1651

1652
        assert_eq!(parser.next_event().unwrap(), Event::EndObject);
1✔
1653
        assert_eq!(parser.next_event().unwrap(), Event::EndDocument);
1✔
1654
    }
1✔
1655

1656
    /// Helper function to test escape sequence parsing with specific buffer size
1657
    fn test_simple_escape_with_buffer_size(buffer_size: usize) -> Result<(), crate::ParseError> {
3✔
1658
        // DEBUG TEST: Simple escape sequence should need minimal buffer
1659
        // JSON: ["hello\\"] = 10 bytes total, should work with ~7 byte buffer
1660
        let json_stream = br#"["hello\\"]"#;
3✔
1661

1662
        println!("Testing escape sequence with buffer size: {}", buffer_size);
3✔
1663
        println!(
3✔
1664
            "JSON input: {:?}",
3✔
1665
            core::str::from_utf8(json_stream).unwrap()
3✔
1666
        );
1667
        let mut buffer = vec![0u8; buffer_size];
3✔
1668
        let mut parser = StreamParser::new(SliceReader::new(json_stream), &mut buffer);
3✔
1669

1670
        // Array start
1671
        match parser.next_event()? {
3✔
1672
            Event::StartArray => println!("  ✅ StartArray OK"),
3✔
1673
            other => panic!("Expected StartArray, got: {:?}", other),
×
1674
        }
1675

1676
        // String with escape
1677
        match parser.next_event()? {
3✔
1678
            Event::String(s) => {
2✔
1679
                println!("  ✅ String OK: '{}'", s.as_str());
2✔
1680
                assert_eq!(s.as_str(), "hello\\");
2✔
1681
            }
1682
            other => panic!("Expected String, got: {:?}", other),
×
1683
        }
1684

1685
        // Array end
1686
        match parser.next_event()? {
2✔
1687
            Event::EndArray => println!("  ✅ EndArray OK"),
2✔
1688
            other => panic!("Expected EndArray, got: {:?}", other),
×
1689
        }
1690

1691
        // End document
1692
        match parser.next_event()? {
2✔
1693
            Event::EndDocument => println!("  ✅ EndDocument OK"),
2✔
1694
            other => panic!("Expected EndDocument, got: {:?}", other),
×
1695
        }
1696

1697
        println!("  🎉 SUCCESS with buffer size: {}", buffer_size);
2✔
1698
        Ok(())
2✔
1699
    }
3✔
1700

1701
    #[test]
1702
    fn test_minimal_buffer_simple_escape_1() {
1✔
1703
        // Buffer size 4 - clearly not enough
1704
        match test_simple_escape_with_buffer_size(4) {
1✔
1705
            Ok(()) => panic!("Expected failure with 4-byte buffer, but succeeded!"),
×
1706
            Err(e) => println!("Expected failure with 4-byte buffer: {:?}", e),
1✔
1707
        }
1708
    }
1✔
1709

1710
    #[test]
1711
    fn test_minimal_buffer_simple_escape_2() {
1✔
1712
        // Buffer size 12 - test if larger buffer avoids compaction bugs
1713
        test_simple_escape_with_buffer_size(12)
1✔
1714
            .expect("12-byte buffer should be sufficient for simple escape");
1✔
1715
    }
1✔
1716

1717
    #[test]
1718
    fn test_minimal_buffer_simple_escape_3() {
1✔
1719
        // Buffer size 24 - known working boundary from stress tests
1720
        test_simple_escape_with_buffer_size(24).expect("24-byte buffer should definitely work");
1✔
1721
    }
1✔
1722

1723
    #[test]
1724
    fn test_surrogate_pair_buffer_boundary_cases() {
1✔
1725
        // Test 7: Surrogate pair split across very small buffer chunks
1726
        let input7 = r#"["\uD801\uDC37"]"#;
1✔
1727
        let mut buffer7 = [0u8; 16]; // Small buffer
1✔
1728
        let reader7 = crate::chunk_reader::ChunkReader::new(input7.as_bytes(), 3); // Tiny chunks
1✔
1729
        let mut parser7 = StreamParser::<_, DefaultConfig>::with_config(reader7, &mut buffer7);
1✔
1730
        assert_eq!(parser7.next_event(), Ok(Event::StartArray));
1✔
1731
        match parser7.next_event() {
1✔
1732
            Ok(Event::String(s)) => {
1✔
1733
                let content = match s {
1✔
1734
                    crate::String::Borrowed(c) => c,
×
1735
                    crate::String::Unescaped(c) => c,
1✔
1736
                };
1737
                assert_eq!(content, "𐐷");
1✔
1738
            }
1739
            other => panic!(
×
1740
                "Expected String with surrogate pair across buffer boundary, got: {:?}",
×
1741
                other
1742
            ),
1743
        }
1744

1745
        // Test 8: Surrogate pair with small buffer (still needs minimum space)
1746
        let input8 = r#"["\uD801\uDC37"]"#;
1✔
1747
        let mut buffer8 = [0u8; 32]; // Small but sufficient buffer
1✔
1748
        let reader8 = crate::chunk_reader::ChunkReader::new(input8.as_bytes(), 6); // Split at surrogate boundary
1✔
1749
        let mut parser8 = StreamParser::<_, DefaultConfig>::with_config(reader8, &mut buffer8);
1✔
1750
        assert_eq!(parser8.next_event(), Ok(Event::StartArray));
1✔
1751
        match parser8.next_event() {
1✔
1752
            Ok(Event::String(s)) => {
1✔
1753
                let content = match s {
1✔
1754
                    crate::String::Borrowed(c) => c,
×
1755
                    crate::String::Unescaped(c) => c,
1✔
1756
                };
1757
                assert_eq!(content, "𐐷");
1✔
1758
            }
1759
            other => panic!(
×
1760
                "Expected String with surrogate pair at small buffer, got: {:?}",
×
1761
                other
1762
            ),
1763
        }
1764
    }
1✔
1765
}
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