facet_format_toml/
parser.rs

1//! Streaming TOML parser implementing the FormatParser trait.
2//!
3//! The key challenge with TOML is "table reopening" - fields for the same struct
4//! can appear at different points in the document:
5//!
6//! ```toml
7//! [foo.bar]
8//! x = 1
9//!
10//! [foo.baz]
11//! z = 3
12//!
13//! [foo.bar]  # reopening!
14//! y = 2
15//! ```
16//!
17//! This parser handles this by treating `StructEnd` and `SequenceEnd` as
18//! "navigating up the graph" rather than "we're done forever". The same applies
19//! to array tables - they can be interleaved with other tables:
20//!
21//! ```toml
22//! [[servers]]
23//! name = "alpha"
24//!
25//! [database]
26//! host = "localhost"
27//!
28//! [[servers]]  # reopening the array!
29//! name = "beta"
30//! ```
31//!
32//! The deserializer with `Partial` in deferred mode handles fields/elements
33//! arriving out of order. No buffering or pre-scanning needed.
34
35extern crate alloc;
36
37use alloc::{
38    borrow::Cow,
39    collections::VecDeque,
40    string::{String, ToString},
41    vec::Vec,
42};
43
44use facet_format::{
45    ContainerKind, FieldEvidence, FieldKey, FieldLocationHint, FormatParser, ParseEvent,
46    ProbeStream, ScalarValue,
47};
48use toml_parser::{
49    ErrorSink, Raw, Source,
50    decoder::ScalarKind,
51    parser::{Event, EventKind, RecursionGuard, parse_document},
52};
53
54use crate::{TomlError, TomlErrorKind};
55
56// ============================================================================
57// Error collection for parsing
58// ============================================================================
59
60/// Collects parse errors from the TOML parser
61struct ParseErrorCollector {
62    error: Option<String>,
63}
64
65impl ParseErrorCollector {
66    fn new() -> Self {
67        Self { error: None }
68    }
69
70    fn take_error(&mut self) -> Option<String> {
71        self.error.take()
72    }
73}
74
75impl ErrorSink for ParseErrorCollector {
76    fn report_error(&mut self, error: toml_parser::ParseError) {
77        if self.error.is_none() {
78            self.error = Some(error.description().to_string());
79        }
80    }
81}
82
83// ============================================================================
84// Path tracking
85// ============================================================================
86
87/// Kind of a path segment - determines what events to emit when navigating.
88#[derive(Debug, Clone, Copy, PartialEq, Eq)]
89enum SegmentKind {
90    /// Standard table `[foo]` - emits StructStart/StructEnd
91    Table,
92    /// Array table element `[[foo]]` - the array itself
93    Array,
94    /// Element inside an array table - emits StructStart/StructEnd
95    ArrayElement,
96}
97
98/// A segment in the current document path.
99#[derive(Debug, Clone)]
100struct PathSegment<'de> {
101    name: Cow<'de, str>,
102    kind: SegmentKind,
103}
104
105// ============================================================================
106// TOML Parser
107// ============================================================================
108
109/// Streaming TOML parser backed by `toml_parser`.
110///
111/// This parser translates TOML's event stream into the `ParseEvent` format
112/// expected by `facet-format`'s deserializer.
113pub struct TomlParser<'de> {
114    /// Original input string.
115    input: &'de str,
116    /// Pre-parsed events from toml_parser.
117    events: Vec<Event>,
118    /// Current position in the event stream.
119    pos: usize,
120    /// Current path in the document with segment kinds.
121    current_path: Vec<PathSegment<'de>>,
122    /// Pending events to emit (navigation when tables change).
123    pending_events: VecDeque<ParseEvent<'de>>,
124    /// Cached event for peek_event().
125    event_peek: Option<ParseEvent<'de>>,
126    /// Whether we've emitted the initial StructStart for the root.
127    root_started: bool,
128    /// Whether we've emitted the final StructEnd for the root.
129    root_ended: bool,
130    /// Stack tracking nested inline containers (inline tables and arrays).
131    /// Each entry is (is_inline_table, deferred_struct_ends) where:
132    /// - is_inline_table: true for inline table, false for array
133    /// - deferred_struct_ends: number of StructEnd events to emit when this container closes
134    inline_stack: Vec<(bool, usize)>,
135    /// The span of the most recently consumed scalar value (for error reporting).
136    last_scalar_span: Option<facet_reflect::Span>,
137}
138
139impl<'de> TomlParser<'de> {
140    /// Create a new TOML parser from a string slice.
141    pub fn new(input: &'de str) -> Result<Self, TomlError> {
142        let source = Source::new(input);
143        let tokens: Vec<_> = source.lex().collect();
144        let mut events: Vec<Event> = Vec::new();
145        let mut guarded = RecursionGuard::new(&mut events, 128);
146        let mut error_collector = ParseErrorCollector::new();
147
148        parse_document(&tokens, &mut guarded, &mut error_collector);
149
150        if let Some(err_msg) = error_collector.take_error() {
151            return Err(TomlError::without_span(TomlErrorKind::Parse(err_msg)));
152        }
153
154        Ok(Self {
155            input,
156            events,
157            pos: 0,
158            current_path: Vec::new(),
159            pending_events: VecDeque::new(),
160            event_peek: None,
161            root_started: false,
162            root_ended: false,
163            inline_stack: Vec::new(),
164            last_scalar_span: None,
165        })
166    }
167
168    /// Get the original input string.
169    pub fn input(&self) -> &'de str {
170        self.input
171    }
172
173    /// Check if an event should be skipped (whitespace, comment, newline).
174    #[inline]
175    fn should_skip(event: &Event) -> bool {
176        matches!(
177            event.kind(),
178            EventKind::Whitespace | EventKind::Comment | EventKind::Newline
179        )
180    }
181
182    /// Peek at the next raw event (skipping whitespace/comments).
183    fn peek_raw(&self) -> Option<&Event> {
184        let mut pos = self.pos;
185        while pos < self.events.len() {
186            let event = &self.events[pos];
187            if !Self::should_skip(event) {
188                return Some(event);
189            }
190            pos += 1;
191        }
192        None
193    }
194
195    /// Consume the next raw event (skipping whitespace/comments).
196    fn next_raw(&mut self) -> Option<&Event> {
197        while self.pos < self.events.len() {
198            let event = &self.events[self.pos];
199            self.pos += 1;
200            if !Self::should_skip(event) {
201                return Some(event);
202            }
203        }
204        None
205    }
206
207    /// Get the string slice for an event's span.
208    fn get_span_str(&self, event: &Event) -> &'de str {
209        let span = event.span();
210        &self.input[span.start()..span.end()]
211    }
212
213    /// Create a Raw from an event for scalar decoding.
214    fn raw_from_event(&self, event: &Event) -> Raw<'de> {
215        let span = event.span();
216        Raw::new_unchecked(
217            &self.input[span.start()..span.end()],
218            event.encoding(),
219            span,
220        )
221    }
222
223    /// Decode a raw TOML value into the appropriate scalar.
224    fn decode_scalar(&self, event: &Event) -> Result<ScalarValue<'de>, TomlError> {
225        let raw = self.raw_from_event(event);
226        let mut output: Cow<'de, str> = Cow::Borrowed("");
227        let kind = raw.decode_scalar(&mut output, &mut ());
228
229        match kind {
230            ScalarKind::String => {
231                // Use the decoded output (handles escapes, quotes, etc.)
232                Ok(ScalarValue::Str(output))
233            }
234            ScalarKind::Boolean(b) => Ok(ScalarValue::Bool(b)),
235            ScalarKind::Integer(radix) => {
236                // Remove underscores for parsing
237                let clean: String = output.chars().filter(|c| *c != '_').collect();
238                let n: i64 = i64::from_str_radix(&clean, radix.value()).map_err(|e| {
239                    TomlError::without_span(TomlErrorKind::InvalidValue {
240                        message: e.to_string(),
241                    })
242                })?;
243                Ok(ScalarValue::I64(n))
244            }
245            ScalarKind::Float => {
246                let clean: String = output.chars().filter(|c| *c != '_').collect();
247                // Handle special float values
248                let f: f64 = match clean.as_str() {
249                    "inf" | "+inf" => f64::INFINITY,
250                    "-inf" => f64::NEG_INFINITY,
251                    "nan" | "+nan" | "-nan" => f64::NAN,
252                    _ => clean.parse().map_err(|e: core::num::ParseFloatError| {
253                        TomlError::without_span(TomlErrorKind::InvalidValue {
254                            message: e.to_string(),
255                        })
256                    })?,
257                };
258                Ok(ScalarValue::F64(f))
259            }
260            ScalarKind::DateTime => {
261                // Keep as string, let facet-reflect handle datetime types
262                Ok(ScalarValue::Str(output))
263            }
264        }
265    }
266
267    /// Parse a dotted key from the current position until we hit a delimiter.
268    /// Returns the components and advances past any key separators.
269    fn parse_dotted_key(&mut self) -> Vec<Cow<'de, str>> {
270        let mut parts = Vec::new();
271
272        loop {
273            let Some(event) = self.peek_raw() else {
274                break;
275            };
276
277            match event.kind() {
278                EventKind::SimpleKey => {
279                    let key = self.decode_key(event);
280                    self.next_raw(); // consume the key
281                    parts.push(key);
282                }
283                EventKind::KeySep => {
284                    // Dot separator - consume and continue
285                    self.next_raw();
286                }
287                _ => break,
288            }
289        }
290
291        parts
292    }
293
294    /// Decode a key from an event.
295    fn decode_key(&self, event: &Event) -> Cow<'de, str> {
296        let raw = self.raw_from_event(event);
297        let mut output: Cow<'de, str> = Cow::Borrowed("");
298        raw.decode_key(&mut output, &mut ());
299        output
300    }
301
302    /// Emit the "end" event for a path segment based on its kind.
303    fn end_event_for_segment(segment: &PathSegment<'_>) -> ParseEvent<'static> {
304        match segment.kind {
305            SegmentKind::Table => ParseEvent::StructEnd,
306            SegmentKind::Array => ParseEvent::SequenceEnd,
307            SegmentKind::ArrayElement => ParseEvent::StructEnd,
308        }
309    }
310
311    /// Compute navigation events to move from current path to target path.
312    ///
313    /// For standard tables `[foo.bar]`, target segments are all `Table` kind.
314    /// For array tables `[[foo.bar]]`, the last segment is `Array` + `ArrayElement`.
315    fn compute_navigation_to_table(
316        &self,
317        target_names: &[Cow<'de, str>],
318    ) -> (Vec<ParseEvent<'de>>, Vec<PathSegment<'de>>) {
319        let mut events = Vec::new();
320
321        // Find common prefix length (by name only)
322        let common_len = self
323            .current_path
324            .iter()
325            .zip(target_names.iter())
326            .take_while(|(seg, name)| &seg.name == *name)
327            .count();
328
329        // Pop up to common ancestor - emit end events in reverse order
330        for segment in self.current_path[common_len..].iter().rev() {
331            events.push(Self::end_event_for_segment(segment));
332        }
333
334        // Navigate down to target - all segments are Tables for [table.path]
335        let mut new_path: Vec<PathSegment<'de>> = self.current_path[..common_len].to_vec();
336        for name in &target_names[common_len..] {
337            events.push(ParseEvent::FieldKey(FieldKey::new(
338                name.clone(),
339                FieldLocationHint::KeyValue,
340            )));
341            events.push(ParseEvent::StructStart(ContainerKind::Object));
342            new_path.push(PathSegment {
343                name: name.clone(),
344                kind: SegmentKind::Table,
345            });
346        }
347
348        (events, new_path)
349    }
350
351    /// Compute navigation events to move to an array table `[[path]]`.
352    ///
353    /// Array tables are special: the last segment becomes Array + ArrayElement,
354    /// meaning we emit FieldKey, SequenceStart, StructStart.
355    ///
356    /// IMPORTANT: For array tables, we must NOT include Array/ArrayElement segments
357    /// in the common prefix. Each `[[name]]` creates a NEW element, so we must fully
358    /// exit any existing array of the same name and re-enter it.
359    fn compute_navigation_to_array_table(
360        &self,
361        target_names: &[Cow<'de, str>],
362    ) -> (Vec<ParseEvent<'de>>, Vec<PathSegment<'de>>) {
363        let mut events = Vec::new();
364
365        // Find common prefix length, but STOP at Array/ArrayElement segments.
366        // We only keep Table segments in the common prefix because:
367        // - Each [[array]] creates a NEW element, requiring full re-entry
368        // - Table segments can be shared (e.g., [[foo.bar]] and [[foo.baz]] share "foo")
369        let common_len = self
370            .current_path
371            .iter()
372            .zip(target_names.iter())
373            .take_while(|(seg, name)| {
374                // Stop at Array or ArrayElement - these must be popped and re-entered
375                if matches!(seg.kind, SegmentKind::Array | SegmentKind::ArrayElement) {
376                    return false;
377                }
378                &seg.name == *name
379            })
380            .count();
381
382        // Pop up to common ancestor
383        for segment in self.current_path[common_len..].iter().rev() {
384            events.push(Self::end_event_for_segment(segment));
385        }
386
387        // Navigate down - all but last are Tables, last is Array + ArrayElement
388        let mut new_path: Vec<PathSegment<'de>> = self.current_path[..common_len].to_vec();
389
390        if target_names.len() > common_len {
391            // Navigate to parent tables first
392            for name in &target_names[common_len..target_names.len() - 1] {
393                events.push(ParseEvent::FieldKey(FieldKey::new(
394                    name.clone(),
395                    FieldLocationHint::KeyValue,
396                )));
397                events.push(ParseEvent::StructStart(ContainerKind::Object));
398                new_path.push(PathSegment {
399                    name: name.clone(),
400                    kind: SegmentKind::Table,
401                });
402            }
403
404            // Last segment is the array table
405            let array_name = target_names.last().unwrap();
406            events.push(ParseEvent::FieldKey(FieldKey::new(
407                array_name.clone(),
408                FieldLocationHint::KeyValue,
409            )));
410            events.push(ParseEvent::SequenceStart(ContainerKind::Array));
411            events.push(ParseEvent::StructStart(ContainerKind::Object));
412
413            new_path.push(PathSegment {
414                name: array_name.clone(),
415                kind: SegmentKind::Array,
416            });
417            new_path.push(PathSegment {
418                name: array_name.clone(),
419                kind: SegmentKind::ArrayElement,
420            });
421        }
422
423        (events, new_path)
424    }
425
426    /// Produce the next parse event.
427    fn produce_event(&mut self) -> Result<Option<ParseEvent<'de>>, TomlError> {
428        // First, drain any pending navigation events
429        if let Some(event) = self.pending_events.pop_front() {
430            return Ok(Some(event));
431        }
432
433        // If we're inside inline containers, handle them specially
434        if !self.inline_stack.is_empty() {
435            return self.produce_inline_event();
436        }
437
438        // Emit root StructStart if we haven't yet
439        if !self.root_started {
440            self.root_started = true;
441            return Ok(Some(ParseEvent::StructStart(ContainerKind::Object)));
442        }
443
444        // Get next raw event
445        let Some(event) = self.peek_raw() else {
446            // EOF - emit end events for remaining path elements, then root
447            if self.root_ended {
448                return Ok(None);
449            }
450
451            // Pop all remaining path segments
452            for segment in self.current_path.iter().rev() {
453                self.pending_events
454                    .push_back(Self::end_event_for_segment(segment));
455            }
456            self.current_path.clear();
457
458            // Final StructEnd for root
459            self.pending_events.push_back(ParseEvent::StructEnd);
460            self.root_ended = true;
461
462            return Ok(self.pending_events.pop_front());
463        };
464
465        match event.kind() {
466            EventKind::StdTableOpen => {
467                // Standard table header [table.path]
468                self.next_raw(); // consume StdTableOpen
469                let path = self.parse_dotted_key();
470
471                // Consume the StdTableClose
472                if let Some(close) = self.peek_raw()
473                    && matches!(close.kind(), EventKind::StdTableClose)
474                {
475                    self.next_raw();
476                }
477
478                // Compute navigation from current path to new table path
479                let (nav_events, new_path) = self.compute_navigation_to_table(&path);
480                for e in nav_events {
481                    self.pending_events.push_back(e);
482                }
483                self.current_path = new_path;
484
485                // If no navigation events were generated, recurse to get next actual event
486                if self.pending_events.is_empty() {
487                    return self.produce_event();
488                }
489
490                Ok(self.pending_events.pop_front())
491            }
492
493            EventKind::ArrayTableOpen => {
494                // Array table header [[table.path]]
495                self.next_raw(); // consume ArrayTableOpen
496                let path = self.parse_dotted_key();
497
498                // Consume the ArrayTableClose
499                if let Some(close) = self.peek_raw()
500                    && matches!(close.kind(), EventKind::ArrayTableClose)
501                {
502                    self.next_raw();
503                }
504
505                // Compute navigation to array table (handles reopening)
506                let (nav_events, new_path) = self.compute_navigation_to_array_table(&path);
507                for e in nav_events {
508                    self.pending_events.push_back(e);
509                }
510                self.current_path = new_path;
511
512                Ok(self.pending_events.pop_front())
513            }
514
515            EventKind::SimpleKey => {
516                // Key-value pair
517                let key_parts = self.parse_dotted_key();
518
519                // Consume the KeyValSep (=)
520                if let Some(sep) = self.peek_raw()
521                    && matches!(sep.kind(), EventKind::KeyValSep)
522                {
523                    self.next_raw();
524                }
525
526                // For dotted keys like `foo.bar.baz = 1`, emit navigation events
527                // to nested structs, then the final key
528                if key_parts.len() > 1 {
529                    // Navigate into nested structs
530                    for name in &key_parts[..key_parts.len() - 1] {
531                        self.pending_events
532                            .push_back(ParseEvent::FieldKey(FieldKey::new(
533                                name.clone(),
534                                FieldLocationHint::KeyValue,
535                            )));
536                        self.pending_events
537                            .push_back(ParseEvent::StructStart(ContainerKind::Object));
538                    }
539
540                    // Emit the final key
541                    let final_key = key_parts.last().unwrap();
542                    self.pending_events
543                        .push_back(ParseEvent::FieldKey(FieldKey::new(
544                            final_key.clone(),
545                            FieldLocationHint::KeyValue,
546                        )));
547
548                    // Track inline stack depth before parsing value
549                    let inline_depth_before = self.inline_stack.len();
550
551                    // Parse the value
552                    self.parse_value_into_pending()?;
553
554                    // Check if we entered an inline container (array or inline table)
555                    let entered_inline_container = self.inline_stack.len() > inline_depth_before;
556
557                    if entered_inline_container {
558                        // Defer the StructEnd events until the inline container closes
559                        let num_deferred = key_parts.len() - 1;
560                        if let Some((_, deferred_closes)) = self.inline_stack.last_mut() {
561                            *deferred_closes += num_deferred;
562                        }
563                    } else {
564                        // Navigate back out of nested structs immediately (for scalar values)
565                        for _ in 0..key_parts.len() - 1 {
566                            self.pending_events.push_back(ParseEvent::StructEnd);
567                        }
568                    }
569
570                    Ok(self.pending_events.pop_front())
571                } else {
572                    // Simple key
573                    let key = key_parts.into_iter().next().unwrap();
574                    self.pending_events
575                        .push_back(ParseEvent::FieldKey(FieldKey::new(
576                            key,
577                            FieldLocationHint::KeyValue,
578                        )));
579
580                    // Parse the value
581                    self.parse_value_into_pending()?;
582
583                    Ok(self.pending_events.pop_front())
584                }
585            }
586
587            EventKind::Error => {
588                let span_str = self.get_span_str(event);
589                Err(TomlError::without_span(TomlErrorKind::Parse(
590                    span_str.to_string(),
591                )))
592            }
593
594            _ => {
595                // Skip unexpected events
596                self.next_raw();
597                self.produce_event()
598            }
599        }
600    }
601
602    /// Parse a value and add its events to pending_events.
603    fn parse_value_into_pending(&mut self) -> Result<(), TomlError> {
604        let Some(event) = self.peek_raw() else {
605            return Err(TomlError::without_span(TomlErrorKind::UnexpectedEof {
606                expected: "value",
607            }));
608        };
609
610        match event.kind() {
611            EventKind::Scalar => {
612                let scalar = self.decode_scalar(event)?;
613                // Track span for error reporting
614                let span = event.span();
615                self.last_scalar_span = Some(facet_reflect::Span::new(
616                    span.start(),
617                    span.end() - span.start(),
618                ));
619                self.next_raw();
620                self.pending_events.push_back(ParseEvent::Scalar(scalar));
621            }
622
623            EventKind::InlineTableOpen => {
624                self.next_raw();
625                self.pending_events
626                    .push_back(ParseEvent::StructStart(ContainerKind::Object));
627                self.inline_stack.push((true, 0)); // true = inline table, 0 deferred closes
628            }
629
630            EventKind::ArrayOpen => {
631                self.next_raw();
632                self.pending_events
633                    .push_back(ParseEvent::SequenceStart(ContainerKind::Array));
634                self.inline_stack.push((false, 0)); // false = array, 0 deferred closes
635            }
636
637            _ => {
638                return Err(TomlError::without_span(TomlErrorKind::UnexpectedType {
639                    expected: "value",
640                    got: "unexpected token",
641                }));
642            }
643        }
644
645        Ok(())
646    }
647
648    /// Produce events while inside inline containers (inline tables or arrays).
649    fn produce_inline_event(&mut self) -> Result<Option<ParseEvent<'de>>, TomlError> {
650        // Check pending events first
651        if let Some(event) = self.pending_events.pop_front() {
652            return Ok(Some(event));
653        }
654
655        let (is_inline_table, _deferred_closes) = *self.inline_stack.last().unwrap();
656
657        let Some(event) = self.peek_raw() else {
658            return Err(TomlError::without_span(TomlErrorKind::UnexpectedEof {
659                expected: if is_inline_table { "}" } else { "]" },
660            }));
661        };
662
663        match event.kind() {
664            EventKind::InlineTableClose if is_inline_table => {
665                self.next_raw();
666                let (_, deferred_closes) = self.inline_stack.pop().unwrap();
667                // Emit the StructEnd for the inline table
668                self.pending_events.push_back(ParseEvent::StructEnd);
669                // Then emit any deferred StructEnd events from dotted keys
670                for _ in 0..deferred_closes {
671                    self.pending_events.push_back(ParseEvent::StructEnd);
672                }
673                Ok(self.pending_events.pop_front())
674            }
675
676            EventKind::ArrayClose if !is_inline_table => {
677                self.next_raw();
678                let (_, deferred_closes) = self.inline_stack.pop().unwrap();
679                // Emit the SequenceEnd for the array
680                self.pending_events.push_back(ParseEvent::SequenceEnd);
681                // Then emit any deferred StructEnd events from dotted keys
682                for _ in 0..deferred_closes {
683                    self.pending_events.push_back(ParseEvent::StructEnd);
684                }
685                Ok(self.pending_events.pop_front())
686            }
687
688            EventKind::ValueSep => {
689                // Comma separator - skip and continue
690                self.next_raw();
691                self.produce_inline_event()
692            }
693
694            EventKind::SimpleKey if is_inline_table => {
695                // Key in inline table
696                let key_parts = self.parse_dotted_key();
697
698                // Consume KeyValSep
699                if let Some(sep) = self.peek_raw()
700                    && matches!(sep.kind(), EventKind::KeyValSep)
701                {
702                    self.next_raw();
703                }
704
705                // Handle dotted keys
706                if key_parts.len() > 1 {
707                    for name in &key_parts[..key_parts.len() - 1] {
708                        self.pending_events
709                            .push_back(ParseEvent::FieldKey(FieldKey::new(
710                                name.clone(),
711                                FieldLocationHint::KeyValue,
712                            )));
713                        self.pending_events
714                            .push_back(ParseEvent::StructStart(ContainerKind::Object));
715                    }
716
717                    let final_key = key_parts.last().unwrap();
718                    self.pending_events
719                        .push_back(ParseEvent::FieldKey(FieldKey::new(
720                            final_key.clone(),
721                            FieldLocationHint::KeyValue,
722                        )));
723
724                    // Track inline stack depth before parsing value
725                    let inline_depth_before = self.inline_stack.len();
726
727                    self.parse_value_into_pending()?;
728
729                    // Check if we entered an inline container (array or inline table)
730                    let entered_inline_container = self.inline_stack.len() > inline_depth_before;
731
732                    if entered_inline_container {
733                        // Defer the StructEnd events until the inline container closes
734                        let num_deferred = key_parts.len() - 1;
735                        if let Some((_, deferred_closes)) = self.inline_stack.last_mut() {
736                            *deferred_closes += num_deferred;
737                        }
738                    } else {
739                        // Navigate back out of nested structs immediately (for scalar values)
740                        for _ in 0..key_parts.len() - 1 {
741                            self.pending_events.push_back(ParseEvent::StructEnd);
742                        }
743                    }
744
745                    Ok(self.pending_events.pop_front())
746                } else {
747                    let key = key_parts.into_iter().next().unwrap();
748                    self.pending_events
749                        .push_back(ParseEvent::FieldKey(FieldKey::new(
750                            key,
751                            FieldLocationHint::KeyValue,
752                        )));
753                    self.parse_value_into_pending()?;
754                    Ok(self.pending_events.pop_front())
755                }
756            }
757
758            EventKind::Scalar if !is_inline_table => {
759                // Value in array
760                let scalar = self.decode_scalar(event)?;
761                // Track span for error reporting
762                let span = event.span();
763                self.last_scalar_span = Some(facet_reflect::Span::new(
764                    span.start(),
765                    span.end() - span.start(),
766                ));
767                self.next_raw();
768                Ok(Some(ParseEvent::Scalar(scalar)))
769            }
770
771            EventKind::InlineTableOpen if !is_inline_table => {
772                // Inline table inside array
773                self.next_raw();
774                self.inline_stack.push((true, 0));
775                Ok(Some(ParseEvent::StructStart(ContainerKind::Object)))
776            }
777
778            EventKind::ArrayOpen if !is_inline_table => {
779                // Nested array
780                self.next_raw();
781                self.inline_stack.push((false, 0));
782                Ok(Some(ParseEvent::SequenceStart(ContainerKind::Array)))
783            }
784
785            _ => {
786                // Skip unexpected
787                self.next_raw();
788                self.produce_inline_event()
789            }
790        }
791    }
792
793    /// Skip the current value (used for skip_value).
794    ///
795    /// This operates at the parse event level, not the raw TOML token level.
796    /// It must handle:
797    /// - Scalars: consume one Scalar event
798    /// - Structs: consume StructStart, all contents, and StructEnd
799    /// - Sequences: consume SequenceStart, all contents, and SequenceEnd
800    fn skip_current_value(&mut self) -> Result<(), TomlError> {
801        // Peek at the next parse event (not raw token)
802        let Some(event) = self.produce_event()? else {
803            return Ok(());
804        };
805
806        match event {
807            ParseEvent::Scalar(_) => {
808                // Scalar value - already consumed by produce_event
809                Ok(())
810            }
811            ParseEvent::StructStart(_) => {
812                // Need to skip the entire struct
813                let mut depth = 1;
814                while depth > 0 {
815                    let Some(event) = self.produce_event()? else {
816                        return Err(TomlError::without_span(TomlErrorKind::UnexpectedEof {
817                            expected: "struct end",
818                        }));
819                    };
820                    match event {
821                        ParseEvent::StructStart(_) => depth += 1,
822                        ParseEvent::StructEnd => depth -= 1,
823                        _ => {}
824                    }
825                }
826                Ok(())
827            }
828            ParseEvent::SequenceStart(_) => {
829                // Need to skip the entire sequence
830                let mut depth = 1;
831                while depth > 0 {
832                    let Some(event) = self.produce_event()? else {
833                        return Err(TomlError::without_span(TomlErrorKind::UnexpectedEof {
834                            expected: "sequence end",
835                        }));
836                    };
837                    match event {
838                        ParseEvent::SequenceStart(_) => depth += 1,
839                        ParseEvent::SequenceEnd => depth -= 1,
840                        _ => {}
841                    }
842                }
843                Ok(())
844            }
845            _ => {
846                // Unexpected event type - shouldn't happen in well-formed input
847                Ok(())
848            }
849        }
850    }
851
852    /// Build probe evidence by scanning ahead.
853    fn build_probe(&self) -> Result<Vec<FieldEvidence<'de>>, TomlError> {
854        let mut evidence = Vec::new();
855        let mut pos = self.pos;
856
857        // Skip to find field keys at current level
858        while pos < self.events.len() {
859            let event = &self.events[pos];
860
861            if Self::should_skip(event) {
862                pos += 1;
863                continue;
864            }
865
866            match event.kind() {
867                EventKind::SimpleKey => {
868                    let key = self.decode_key(event);
869                    pos += 1;
870
871                    // Skip to value
872                    while pos < self.events.len() {
873                        let e = &self.events[pos];
874                        if !Self::should_skip(e) {
875                            break;
876                        }
877                        pos += 1;
878                    }
879
880                    // Skip KeySep (dots) and additional key parts
881                    while pos < self.events.len() {
882                        let e = &self.events[pos];
883                        if Self::should_skip(e) {
884                            pos += 1;
885                            continue;
886                        }
887                        if matches!(e.kind(), EventKind::KeySep | EventKind::SimpleKey) {
888                            pos += 1;
889                            continue;
890                        }
891                        break;
892                    }
893
894                    // Skip KeyValSep (=)
895                    if pos < self.events.len() {
896                        let e = &self.events[pos];
897                        if matches!(e.kind(), EventKind::KeyValSep) {
898                            pos += 1;
899                        }
900                    }
901
902                    // Skip whitespace to value
903                    while pos < self.events.len() {
904                        let e = &self.events[pos];
905                        if !Self::should_skip(e) {
906                            break;
907                        }
908                        pos += 1;
909                    }
910
911                    // Try to get scalar value
912                    let scalar_value = if pos < self.events.len() {
913                        let e = &self.events[pos];
914                        if matches!(e.kind(), EventKind::Scalar) {
915                            self.decode_scalar(e).ok()
916                        } else {
917                            None
918                        }
919                    } else {
920                        None
921                    };
922
923                    if let Some(sv) = scalar_value {
924                        evidence.push(FieldEvidence::with_scalar_value(
925                            key,
926                            FieldLocationHint::KeyValue,
927                            None,
928                            sv,
929                            None,
930                        ));
931                    } else {
932                        evidence.push(FieldEvidence::new(
933                            key,
934                            FieldLocationHint::KeyValue,
935                            None,
936                            None,
937                        ));
938                    }
939                }
940
941                EventKind::StdTableOpen
942                | EventKind::ArrayTableOpen
943                | EventKind::InlineTableClose
944                | EventKind::ArrayClose => {
945                    // Stop scanning at table boundaries or container ends
946                    break;
947                }
948
949                _ => {
950                    pos += 1;
951                }
952            }
953        }
954
955        Ok(evidence)
956    }
957}
958
959impl<'de> FormatParser<'de> for TomlParser<'de> {
960    type Error = TomlError;
961    type Probe<'a>
962        = TomlProbe<'de>
963    where
964        Self: 'a;
965
966    fn next_event(&mut self) -> Result<Option<ParseEvent<'de>>, Self::Error> {
967        if let Some(event) = self.event_peek.take() {
968            return Ok(Some(event));
969        }
970        self.produce_event()
971    }
972
973    fn peek_event(&mut self) -> Result<Option<ParseEvent<'de>>, Self::Error> {
974        if let Some(event) = self.event_peek.clone() {
975            return Ok(Some(event));
976        }
977        let event = self.produce_event()?;
978        if let Some(ref e) = event {
979            self.event_peek = Some(e.clone());
980        }
981        Ok(event)
982    }
983
984    fn skip_value(&mut self) -> Result<(), Self::Error> {
985        debug_assert!(
986            self.event_peek.is_none(),
987            "skip_value called while an event is buffered"
988        );
989        self.skip_current_value()
990    }
991
992    fn begin_probe(&mut self) -> Result<Self::Probe<'_>, Self::Error> {
993        let evidence = self.build_probe()?;
994        Ok(TomlProbe { evidence, idx: 0 })
995    }
996
997    fn capture_raw(&mut self) -> Result<Option<&'de str>, Self::Error> {
998        // TOML doesn't support raw capture (unlike JSON)
999        self.skip_value()?;
1000        Ok(None)
1001    }
1002
1003    fn current_span(&self) -> Option<facet_reflect::Span> {
1004        self.last_scalar_span
1005    }
1006}
1007
1008/// Probe stream for TOML.
1009pub struct TomlProbe<'de> {
1010    evidence: Vec<FieldEvidence<'de>>,
1011    idx: usize,
1012}
1013
1014impl<'de> ProbeStream<'de> for TomlProbe<'de> {
1015    type Error = TomlError;
1016
1017    fn next(&mut self) -> Result<Option<FieldEvidence<'de>>, Self::Error> {
1018        if self.idx >= self.evidence.len() {
1019            Ok(None)
1020        } else {
1021            let ev = self.evidence[self.idx].clone();
1022            self.idx += 1;
1023            Ok(Some(ev))
1024        }
1025    }
1026}
1027
1028// ============================================================================
1029// Public API
1030// ============================================================================
1031
1032/// Deserialize a TOML string into a type.
1033pub fn from_str<'de, T>(input: &'de str) -> Result<T, TomlError>
1034where
1035    T: facet_core::Facet<'de>,
1036{
1037    let parser = TomlParser::new(input)?;
1038    let mut deserializer = facet_format::FormatDeserializer::new(parser);
1039
1040    deserializer.deserialize().map_err(|e| {
1041        let err = match e {
1042            facet_format::DeserializeError::Parser(e) => e,
1043            facet_format::DeserializeError::Reflect { ref error, span } => {
1044                let mut toml_err = TomlError::from(error.clone());
1045                // Use the span from the deserializer if available
1046                if span.is_some() {
1047                    toml_err.span = span;
1048                }
1049                toml_err
1050            }
1051            facet_format::DeserializeError::UnexpectedEof { expected } => {
1052                TomlError::without_span(TomlErrorKind::UnexpectedEof { expected })
1053            }
1054            facet_format::DeserializeError::Unsupported(msg) => {
1055                TomlError::without_span(TomlErrorKind::InvalidValue { message: msg })
1056            }
1057            facet_format::DeserializeError::TypeMismatch { expected, got } => {
1058                TomlError::without_span(TomlErrorKind::InvalidValue {
1059                    message: alloc::format!("type mismatch: expected {}, got {}", expected, got),
1060                })
1061            }
1062            facet_format::DeserializeError::UnknownField(field) => {
1063                TomlError::without_span(TomlErrorKind::UnknownField {
1064                    field,
1065                    expected: Vec::new(),
1066                    suggestion: None,
1067                })
1068            }
1069            facet_format::DeserializeError::CannotBorrow { message, .. } => {
1070                TomlError::without_span(TomlErrorKind::InvalidValue { message })
1071            }
1072            facet_format::DeserializeError::MissingField { field, .. } => {
1073                TomlError::without_span(TomlErrorKind::MissingField {
1074                    field,
1075                    table_start: None,
1076                    table_end: None,
1077                })
1078            }
1079        };
1080        // Attach source code to all errors for better diagnostics
1081        err.with_source(input)
1082    })
1083}
1084
1085#[cfg(test)]
1086mod tests {
1087    use super::*;
1088
1089    /// Helper to collect all events from a parser
1090    fn collect_events<'de>(parser: &mut TomlParser<'de>) -> Vec<ParseEvent<'de>> {
1091        let mut events = Vec::new();
1092        while let Ok(Some(event)) = parser.next_event() {
1093            events.push(event);
1094        }
1095        events
1096    }
1097
1098    /// Helper to format events for debugging
1099    fn format_events(events: &[ParseEvent<'_>]) -> String {
1100        events
1101            .iter()
1102            .map(|e| format!("{:?}", e))
1103            .collect::<Vec<_>>()
1104            .join("\n")
1105    }
1106
1107    #[test]
1108    fn test_simple_key_value() {
1109        let input = r#"
1110name = "test"
1111value = 42
1112"#;
1113        let mut parser = TomlParser::new(input).unwrap();
1114
1115        // StructStart (root)
1116        assert!(matches!(
1117            parser.next_event().unwrap(),
1118            Some(ParseEvent::StructStart(ContainerKind::Object))
1119        ));
1120
1121        // FieldKey("name")
1122        assert!(matches!(
1123            parser.next_event().unwrap(),
1124            Some(ParseEvent::FieldKey(key)) if key.name == "name"
1125        ));
1126
1127        // Scalar("test")
1128        assert!(matches!(
1129            parser.next_event().unwrap(),
1130            Some(ParseEvent::Scalar(ScalarValue::Str(s))) if s == "test"
1131        ));
1132
1133        // FieldKey("value")
1134        assert!(matches!(
1135            parser.next_event().unwrap(),
1136            Some(ParseEvent::FieldKey(key)) if key.name == "value"
1137        ));
1138
1139        // Scalar(42)
1140        assert!(matches!(
1141            parser.next_event().unwrap(),
1142            Some(ParseEvent::Scalar(ScalarValue::I64(42)))
1143        ));
1144
1145        // StructEnd (root)
1146        assert!(matches!(
1147            parser.next_event().unwrap(),
1148            Some(ParseEvent::StructEnd)
1149        ));
1150
1151        // EOF
1152        assert!(parser.next_event().unwrap().is_none());
1153    }
1154
1155    #[test]
1156    fn test_table_header() {
1157        let input = r#"
1158[server]
1159host = "localhost"
1160port = 8080
1161"#;
1162        let mut parser = TomlParser::new(input).unwrap();
1163        let events = collect_events(&mut parser);
1164
1165        // Expected: StructStart, FieldKey(server), StructStart, FieldKey(host), Scalar,
1166        //           FieldKey(port), Scalar, StructEnd, StructEnd
1167        assert!(matches!(&events[0], ParseEvent::StructStart(_)));
1168        assert!(matches!(&events[1], ParseEvent::FieldKey(k) if k.name == "server"));
1169        assert!(matches!(&events[2], ParseEvent::StructStart(_)));
1170        assert!(matches!(&events[3], ParseEvent::FieldKey(k) if k.name == "host"));
1171        assert!(matches!(&events[4], ParseEvent::Scalar(ScalarValue::Str(s)) if s == "localhost"));
1172        assert!(matches!(&events[5], ParseEvent::FieldKey(k) if k.name == "port"));
1173        assert!(matches!(
1174            &events[6],
1175            ParseEvent::Scalar(ScalarValue::I64(8080))
1176        ));
1177        assert!(matches!(&events[7], ParseEvent::StructEnd)); // server
1178        assert!(matches!(&events[8], ParseEvent::StructEnd)); // root
1179    }
1180
1181    #[test]
1182    fn test_array_table() {
1183        let input = r#"
1184[[servers]]
1185name = "alpha"
1186
1187[[servers]]
1188name = "beta"
1189"#;
1190        let mut parser = TomlParser::new(input).unwrap();
1191        let events = collect_events(&mut parser);
1192
1193        // Expected sequence:
1194        // StructStart (root)
1195        // FieldKey(servers), SequenceStart, StructStart (element 0)
1196        // FieldKey(name), Scalar(alpha)
1197        // StructEnd (element 0), SequenceEnd
1198        // FieldKey(servers), SequenceStart, StructStart (element 1) <- REOPEN
1199        // FieldKey(name), Scalar(beta)
1200        // StructEnd (element 1), SequenceEnd
1201        // StructEnd (root)
1202
1203        let event_str = format_events(&events);
1204        eprintln!("Events:\n{}", event_str);
1205
1206        assert!(matches!(&events[0], ParseEvent::StructStart(_))); // root
1207        assert!(matches!(&events[1], ParseEvent::FieldKey(k) if k.name == "servers"));
1208        assert!(matches!(&events[2], ParseEvent::SequenceStart(_)));
1209        assert!(matches!(&events[3], ParseEvent::StructStart(_))); // element 0
1210        assert!(matches!(&events[4], ParseEvent::FieldKey(k) if k.name == "name"));
1211        assert!(matches!(&events[5], ParseEvent::Scalar(ScalarValue::Str(s)) if s == "alpha"));
1212        assert!(matches!(&events[6], ParseEvent::StructEnd)); // element 0
1213        assert!(matches!(&events[7], ParseEvent::SequenceEnd)); // servers array (navigate up)
1214
1215        // Reopen servers array
1216        assert!(matches!(&events[8], ParseEvent::FieldKey(k) if k.name == "servers"));
1217        assert!(matches!(&events[9], ParseEvent::SequenceStart(_)));
1218        assert!(matches!(&events[10], ParseEvent::StructStart(_))); // element 1
1219        assert!(matches!(&events[11], ParseEvent::FieldKey(k) if k.name == "name"));
1220        assert!(matches!(&events[12], ParseEvent::Scalar(ScalarValue::Str(s)) if s == "beta"));
1221    }
1222
1223    #[test]
1224    fn test_interleaved_array_table() {
1225        // This is the tricky case: array table elements interleaved with other tables
1226        let input = r#"
1227[[servers]]
1228name = "alpha"
1229
1230[database]
1231host = "localhost"
1232
1233[[servers]]
1234name = "beta"
1235"#;
1236        let mut parser = TomlParser::new(input).unwrap();
1237        let events = collect_events(&mut parser);
1238
1239        let event_str = format_events(&events);
1240        eprintln!("Interleaved events:\n{}", event_str);
1241
1242        // The key verification: we should see servers array opened, closed,
1243        // then database, then servers reopened
1244        let mut saw_servers_first = false;
1245        let mut saw_database = false;
1246        let mut saw_servers_second = false;
1247        let mut servers_count = 0;
1248
1249        for event in events.iter() {
1250            if let ParseEvent::FieldKey(k) = event {
1251                if k.name == "servers" {
1252                    servers_count += 1;
1253                    if !saw_database {
1254                        saw_servers_first = true;
1255                    } else {
1256                        saw_servers_second = true;
1257                    }
1258                } else if k.name == "database" {
1259                    saw_database = true;
1260                }
1261            }
1262        }
1263
1264        assert!(saw_servers_first, "Should see servers before database");
1265        assert!(saw_database, "Should see database");
1266        assert!(
1267            saw_servers_second,
1268            "Should see servers reopened after database"
1269        );
1270        assert_eq!(servers_count, 2, "Should have two FieldKey(servers) events");
1271    }
1272
1273    #[test]
1274    fn test_table_reopening() {
1275        // Standard table reopening (not array table)
1276        let input = r#"
1277[foo.bar]
1278x = 1
1279
1280[foo.baz]
1281z = 3
1282
1283[foo.bar]
1284y = 2
1285"#;
1286        let mut parser = TomlParser::new(input).unwrap();
1287        let events = collect_events(&mut parser);
1288
1289        let event_str = format_events(&events);
1290        eprintln!("Table reopen events:\n{}", event_str);
1291
1292        // Count how many times we see FieldKey("bar")
1293        let bar_count = events
1294            .iter()
1295            .filter(|e| matches!(e, ParseEvent::FieldKey(k) if k.name == "bar"))
1296            .count();
1297
1298        assert_eq!(bar_count, 2, "Should see bar twice (reopened)");
1299    }
1300
1301    #[test]
1302    fn test_dotted_key() {
1303        let input = r#"
1304foo.bar.baz = 1
1305"#;
1306        let mut parser = TomlParser::new(input).unwrap();
1307        let events = collect_events(&mut parser);
1308
1309        let event_str = format_events(&events);
1310        eprintln!("Dotted key events:\n{}", event_str);
1311
1312        // Expected: StructStart, FieldKey(foo), StructStart, FieldKey(bar), StructStart,
1313        //           FieldKey(baz), Scalar(1), StructEnd, StructEnd, StructEnd
1314        assert!(matches!(&events[0], ParseEvent::StructStart(_))); // root
1315        assert!(matches!(&events[1], ParseEvent::FieldKey(k) if k.name == "foo"));
1316        assert!(matches!(&events[2], ParseEvent::StructStart(_)));
1317        assert!(matches!(&events[3], ParseEvent::FieldKey(k) if k.name == "bar"));
1318        assert!(matches!(&events[4], ParseEvent::StructStart(_)));
1319        assert!(matches!(&events[5], ParseEvent::FieldKey(k) if k.name == "baz"));
1320        assert!(matches!(
1321            &events[6],
1322            ParseEvent::Scalar(ScalarValue::I64(1))
1323        ));
1324        // Three StructEnds for the nested structs, plus root
1325        assert!(matches!(&events[7], ParseEvent::StructEnd));
1326        assert!(matches!(&events[8], ParseEvent::StructEnd));
1327        assert!(matches!(&events[9], ParseEvent::StructEnd));
1328    }
1329
1330    #[test]
1331    fn test_inline_table() {
1332        let input = r#"
1333server = { host = "localhost", port = 8080 }
1334"#;
1335        let mut parser = TomlParser::new(input).unwrap();
1336        let events = collect_events(&mut parser);
1337
1338        let event_str = format_events(&events);
1339        eprintln!("Inline table events:\n{}", event_str);
1340
1341        assert!(matches!(&events[0], ParseEvent::StructStart(_))); // root
1342        assert!(matches!(&events[1], ParseEvent::FieldKey(k) if k.name == "server"));
1343        assert!(matches!(&events[2], ParseEvent::StructStart(_))); // inline table
1344        assert!(matches!(&events[3], ParseEvent::FieldKey(k) if k.name == "host"));
1345        assert!(matches!(&events[4], ParseEvent::Scalar(ScalarValue::Str(s)) if s == "localhost"));
1346        assert!(matches!(&events[5], ParseEvent::FieldKey(k) if k.name == "port"));
1347        assert!(matches!(
1348            &events[6],
1349            ParseEvent::Scalar(ScalarValue::I64(8080))
1350        ));
1351        assert!(matches!(&events[7], ParseEvent::StructEnd)); // inline table
1352        assert!(matches!(&events[8], ParseEvent::StructEnd)); // root
1353    }
1354
1355    #[test]
1356    fn test_inline_array() {
1357        let input = r#"
1358numbers = [1, 2, 3]
1359"#;
1360        let mut parser = TomlParser::new(input).unwrap();
1361        let events = collect_events(&mut parser);
1362
1363        let event_str = format_events(&events);
1364        eprintln!("Inline array events:\n{}", event_str);
1365
1366        assert!(matches!(&events[0], ParseEvent::StructStart(_))); // root
1367        assert!(matches!(&events[1], ParseEvent::FieldKey(k) if k.name == "numbers"));
1368        assert!(matches!(&events[2], ParseEvent::SequenceStart(_)));
1369        assert!(matches!(
1370            &events[3],
1371            ParseEvent::Scalar(ScalarValue::I64(1))
1372        ));
1373        assert!(matches!(
1374            &events[4],
1375            ParseEvent::Scalar(ScalarValue::I64(2))
1376        ));
1377        assert!(matches!(
1378            &events[5],
1379            ParseEvent::Scalar(ScalarValue::I64(3))
1380        ));
1381        assert!(matches!(&events[6], ParseEvent::SequenceEnd));
1382        assert!(matches!(&events[7], ParseEvent::StructEnd)); // root
1383    }
1384
1385    // ========================================================================
1386    // Deserialization tests (full pipeline)
1387    // ========================================================================
1388
1389    #[test]
1390    fn test_deserialize_simple_struct() {
1391        #[derive(Debug, PartialEq, facet::Facet)]
1392        struct Config {
1393            name: String,
1394            port: i64,
1395            enabled: bool,
1396        }
1397
1398        let input = r#"
1399name = "myapp"
1400port = 8080
1401enabled = true
1402"#;
1403        let config: Config = from_str(input).unwrap();
1404        assert_eq!(config.name, "myapp");
1405        assert_eq!(config.port, 8080);
1406        assert!(config.enabled);
1407    }
1408
1409    #[test]
1410    fn test_deserialize_nested_table() {
1411        #[derive(Debug, PartialEq, facet::Facet)]
1412        struct Config {
1413            server: Server,
1414        }
1415
1416        #[derive(Debug, PartialEq, facet::Facet)]
1417        struct Server {
1418            host: String,
1419            port: i64,
1420        }
1421
1422        let input = r#"
1423[server]
1424host = "localhost"
1425port = 3000
1426"#;
1427        let config: Config = from_str(input).unwrap();
1428        assert_eq!(config.server.host, "localhost");
1429        assert_eq!(config.server.port, 3000);
1430    }
1431
1432    #[test]
1433    fn test_deserialize_array_table() {
1434        #[derive(Debug, PartialEq, facet::Facet)]
1435        struct Config {
1436            servers: Vec<Server>,
1437        }
1438
1439        #[derive(Debug, PartialEq, facet::Facet)]
1440        struct Server {
1441            name: String,
1442        }
1443
1444        let input = r#"
1445[[servers]]
1446name = "alpha"
1447
1448[[servers]]
1449name = "beta"
1450
1451[[servers]]
1452name = "gamma"
1453"#;
1454        let config: Config = from_str(input).unwrap();
1455        assert_eq!(config.servers.len(), 3);
1456        assert_eq!(config.servers[0].name, "alpha");
1457        assert_eq!(config.servers[1].name, "beta");
1458        assert_eq!(config.servers[2].name, "gamma");
1459    }
1460
1461    #[test]
1462    fn test_deserialize_interleaved_array_table() {
1463        #[derive(Debug, PartialEq, facet::Facet)]
1464        struct Config {
1465            servers: Vec<Server>,
1466            database: Database,
1467        }
1468
1469        #[derive(Debug, PartialEq, facet::Facet)]
1470        struct Server {
1471            name: String,
1472        }
1473
1474        #[derive(Debug, PartialEq, facet::Facet)]
1475        struct Database {
1476            host: String,
1477        }
1478
1479        let input = r#"
1480[[servers]]
1481name = "alpha"
1482
1483[database]
1484host = "localhost"
1485
1486[[servers]]
1487name = "beta"
1488"#;
1489        let config: Config = from_str(input).unwrap();
1490        assert_eq!(config.servers.len(), 2);
1491        assert_eq!(config.servers[0].name, "alpha");
1492        assert_eq!(config.servers[1].name, "beta");
1493        assert_eq!(config.database.host, "localhost");
1494    }
1495
1496    #[test]
1497    fn test_issue_1399_array_of_tables_only_parses_last_entry() {
1498        // Regression test for #1399: array-of-tables should collect all entries, not just the last one
1499        // The bug is specifically with Option<Vec<T>>, not Vec<T>
1500        #[derive(Debug, PartialEq, facet::Facet)]
1501        struct Lockfile {
1502            version: Option<u32>,
1503            package: Option<Vec<Package>>,
1504        }
1505
1506        #[derive(Debug, PartialEq, facet::Facet)]
1507        struct Package {
1508            name: String,
1509            version: String,
1510        }
1511
1512        let input = r#"
1513version = 4
1514
1515[[package]]
1516name = "myapp"
1517version = "0.1.0"
1518
1519[[package]]
1520name = "aho-corasick"
1521version = "1.1.2"
1522"#;
1523        let lockfile: Lockfile = from_str(input).unwrap();
1524
1525        assert_eq!(lockfile.version, Some(4));
1526
1527        let packages = lockfile.package.expect("package field should be Some");
1528        assert_eq!(
1529            packages.len(),
1530            2,
1531            "Should parse both package entries, not just the last one"
1532        );
1533
1534        assert_eq!(packages[0].name, "myapp");
1535        assert_eq!(packages[0].version, "0.1.0");
1536
1537        assert_eq!(packages[1].name, "aho-corasick");
1538        assert_eq!(packages[1].version, "1.1.2");
1539    }
1540
1541    #[test]
1542    fn test_deserialize_inline_table() {
1543        #[derive(Debug, PartialEq, facet::Facet)]
1544        struct Config {
1545            point: Point,
1546        }
1547
1548        #[derive(Debug, PartialEq, facet::Facet)]
1549        struct Point {
1550            x: i64,
1551            y: i64,
1552        }
1553
1554        let input = r#"point = { x = 10, y = 20 }"#;
1555        let config: Config = from_str(input).unwrap();
1556        assert_eq!(config.point.x, 10);
1557        assert_eq!(config.point.y, 20);
1558    }
1559
1560    #[test]
1561    fn test_deserialize_inline_array() {
1562        #[derive(Debug, PartialEq, facet::Facet)]
1563        struct Config {
1564            values: Vec<i64>,
1565        }
1566
1567        let input = r#"values = [1, 2, 3, 4, 5]"#;
1568        let config: Config = from_str(input).unwrap();
1569        assert_eq!(config.values, vec![1, 2, 3, 4, 5]);
1570    }
1571
1572    #[test]
1573    fn test_deserialize_dotted_key() {
1574        #[derive(Debug, PartialEq, facet::Facet)]
1575        struct Config {
1576            foo: Foo,
1577        }
1578
1579        #[derive(Debug, PartialEq, facet::Facet)]
1580        struct Foo {
1581            bar: Bar,
1582        }
1583
1584        #[derive(Debug, PartialEq, facet::Facet)]
1585        struct Bar {
1586            baz: i64,
1587        }
1588
1589        let input = r#"foo.bar.baz = 42"#;
1590        let config: Config = from_str(input).unwrap();
1591        assert_eq!(config.foo.bar.baz, 42);
1592    }
1593
1594    // NOTE: Table reopening deserialization is a known limitation.
1595    //
1596    // TOML allows fields for the same struct to appear at different points in the document:
1597    //
1598    //   [foo.bar]
1599    //   x = 1
1600    //   [foo.baz]
1601    //   z = 3
1602    //   [foo.bar]  # reopening!
1603    //   y = 2
1604    //
1605    // The parser correctly emits events with StructEnd as "navigation" (not finalization),
1606    // but facet-format's deserializer validates structs at StructEnd and fails because
1607    // 'y' hasn't been seen yet.
1608    //
1609    // Solutions require either:
1610    // 1. Adding deferred validation to facet-format (don't validate until EOF)
1611    // 2. Reordering events in the parser so each struct is contiguous
1612    //
1613    // The event stream test (test_table_reopening) passes because it only checks events,
1614    // not the full deserialization pipeline.
1615    #[test]
1616    #[ignore = "table reopening requires deferred validation in facet-format"]
1617    fn test_deserialize_table_reopening() {
1618        #[derive(Debug, PartialEq, facet::Facet)]
1619        struct Config {
1620            foo: Foo,
1621        }
1622
1623        #[derive(Debug, PartialEq, facet::Facet)]
1624        struct Foo {
1625            bar: Bar,
1626            baz: Baz,
1627        }
1628
1629        #[derive(Debug, PartialEq, facet::Facet)]
1630        struct Bar {
1631            x: i64,
1632            y: i64,
1633        }
1634
1635        #[derive(Debug, PartialEq, facet::Facet)]
1636        struct Baz {
1637            z: i64,
1638        }
1639
1640        let input = r#"
1641[foo.bar]
1642x = 1
1643
1644[foo.baz]
1645z = 3
1646
1647[foo.bar]
1648y = 2
1649"#;
1650        let config: Config = from_str(input).unwrap();
1651        assert_eq!(config.foo.bar.x, 1);
1652        assert_eq!(config.foo.bar.y, 2);
1653        assert_eq!(config.foo.baz.z, 3);
1654    }
1655}