facet_format/deserializer/mod.rs
1//! # Format Deserializer
2//!
3//! This module provides a generic deserializer that drives format-specific parsers
4//! (JSON, TOML, etc.) directly into facet's `Partial` builder.
5//!
6//! ## Error Handling Philosophy
7//!
8//! Good error messages are critical for developer experience. When deserialization
9//! fails, users need to know **where** the error occurred (both in the input and
10//! in the type structure) and **what** went wrong. This module enforces several
11//! invariants to ensure high-quality error messages.
12//!
13//! ### Always Include a Span
14//!
15//! Every error should include a `Span` pointing to the location in the input where
16//! the error occurred. This allows tools to highlight the exact position:
17//!
18//! ```text
19//! error: expected integer, got string
20//! --> config.toml:15:12
21//! |
22//! 15 | count = "not a number"
23//! | ^^^^^^^^^^^^^^
24//! ```
25//!
26//! The deserializer tracks `last_span` which is updated after consuming each event.
27//! When constructing errors manually, always use `self.last_span`. The `SpanGuard`
28//! RAII type sets a thread-local span that the `From<ReflectError>` impl uses
29//! automatically.
30//!
31//! ### Always Include a Path
32//!
33//! Every error should include a `Path` showing the location in the type structure.
34//! This is especially important for nested types where the span alone doesn't tell
35//! you which field failed:
36//!
37//! ```text
38//! error: missing required field `email`
39//! --> config.toml:10:5
40//! |
41//! 10 | [users.alice]
42//! | ^^^^^^^^^^^^^
43//! |
44//! = path: config.users["alice"].contact
45//! ```
46//!
47//! When constructing errors, use `wip.path()` to get the current path through the
48//! type structure. The `Partial` tracks this automatically as you descend into
49//! fields, list items, map keys, etc.
50//!
51//! ### Error Construction Patterns
52//!
53//! **For errors during deserialization (when `wip` is available):**
54//!
55//! ```ignore
56//! return Err(DeserializeError {
57//! span: Some(self.last_span),
58//! path: Some(wip.path()),
59//! kind: DeserializeErrorKind::UnexpectedToken { ... },
60//! });
61//! ```
62//!
63//! **For errors from `Partial` methods (via `?` operator):**
64//!
65//! The `From<ReflectError>` impl automatically captures the span from the
66//! thread-local `SpanGuard` and the path from the `ReflectError`. Just use `?`:
67//!
68//! ```ignore
69//! let _guard = SpanGuard::new(self.last_span);
70//! wip = wip.begin_field("name")?; // Error automatically has span + path
71//! ```
72//!
73//! **For errors with `DeserializeErrorKind::with_span()`:**
74//!
75//! When you only have an error kind and span (no `wip` for path):
76//!
77//! ```ignore
78//! return Err(DeserializeErrorKind::UnexpectedEof { expected: "value" }
79//! .with_span(self.last_span));
80//! ```
81//!
82//! Note: `with_span()` sets `path: None`. Prefer the full struct when you have a path.
83//!
84//! ### ReflectError Conversion
85//!
86//! Errors from `facet-reflect` (the `Partial` API) are converted via `From<ReflectError>`.
87//! This impl:
88//!
89//! 1. Captures the span from the thread-local `CURRENT_SPAN` (set by `SpanGuard`)
90//! 2. Preserves the path from `ReflectError::path`
91//! 3. Wraps the error kind in `DeserializeErrorKind::Reflect`
92//!
93//! This means you must have an active `SpanGuard` when calling `Partial` methods
94//! that might fail. The guard is typically created at the start of each
95//! deserialization method:
96//!
97//! ```ignore
98//! pub fn deserialize_struct(&mut self, wip: Partial) -> Result<...> {
99//! let _guard = SpanGuard::new(self.last_span);
100//! // ... Partial methods can now use ? and errors will have spans
101//! }
102//! ```
103//!
104//! ## Method Chaining with `.with()`
105//!
106//! The `Partial` API provides a `.with()` method for cleaner chaining when you
107//! need to call deserializer methods (which take `&mut self`) in the middle of
108//! a chain:
109//!
110//! ```ignore
111//! // Instead of:
112//! wip = wip.begin_field("name")?;
113//! wip = self.deserialize_into(wip, MetaSource::FromEvents)?;
114//! wip = wip.end()?;
115//!
116//! // Use:
117//! wip = wip
118//! .begin_field("name")?
119//! .with(|w| self.deserialize_into(w))?
120//! .end()?;
121//! ```
122//!
123//! This keeps the "begin/deserialize/end" pattern visually grouped and makes
124//! the nesting structure clearer.
125
126use std::collections::VecDeque;
127use std::marker::PhantomData;
128use std::sync::Arc;
129
130use facet_core::{Facet, Shape};
131use facet_reflect::{HeapValue, Partial, Span};
132use facet_solver::{FieldInfo, KeyResult, SatisfyResult, Schema, Solver};
133
134use crate::{FormatParser, ParseEvent, type_plan_cache::cached_type_plan_arc};
135
136mod error;
137pub use entry::MetaSource;
138pub use error::*;
139
140/// Convenience setters for string etc.
141mod setters;
142
143/// Entry point for deserialization
144mod entry;
145
146/// Deserialization of dynamic values
147mod dynamic;
148
149/// Enum handling
150mod eenum;
151
152/// Smart pointers (Box, Arc, etc.)
153mod pointer;
154
155/// Check if a scalar matches a target shape
156mod scalar_matches;
157
158/// Simple struct deserialization (no flatten)
159mod struct_simple;
160
161/// Not-so-simple struct deserialization (flatten)
162mod struct_with_flatten;
163
164/// Path navigation for flattened struct deserialization
165mod path_navigator;
166
167/// Default size of the event buffer for batched parsing.
168pub const DEFAULT_EVENT_BUFFER_SIZE: usize = 512;
169
170/// Save point for the deserializer, capturing both parser state and event buffer.
171///
172/// This ensures that when we restore, we restore BOTH the parser position AND
173/// the buffered events that had already been read from the parser.
174struct DeserializerSavePoint<'input> {
175 parser_save_point: crate::SavePoint,
176 event_buffer: VecDeque<ParseEvent<'input>>,
177}
178
179/// Generic deserializer that drives a format-specific parser directly into `Partial`.
180///
181/// The const generic `BORROW` controls whether string data can be borrowed:
182/// - `BORROW=true`: strings without escapes are borrowed from input
183/// - `BORROW=false`: all strings are owned
184///
185/// The lifetime `'parser` is the lifetime of the parser itself, which may be shorter
186/// than `'input` (e.g., for streaming parsers that produce owned data but contain
187/// references to internal state).
188pub struct FormatDeserializer<'parser, 'input, const BORROW: bool> {
189 parser: &'parser mut dyn FormatParser<'input>,
190
191 /// The span of the most recently consumed event (for error reporting).
192 last_span: Span,
193
194 /// Buffer for batched event reading (push back, pop front).
195 event_buffer: VecDeque<ParseEvent<'input>>,
196 /// Maximum number of events to buffer at once.
197 buffer_capacity: usize,
198
199 /// Whether the parser is non-self-describing (postcard, etc.).
200 /// Gates the schema-driven hints (`hint_struct_fields`, `hint_enum`,
201 /// `hint_scalar_type`, ...) that only those formats consume.
202 /// Computed once at construction time.
203 is_non_self_describing: bool,
204
205 /// Whether to bypass event buffering. True for non-self-describing
206 /// formats and for parsers that need container hints (Lua): hints clear
207 /// or reclassify the parser's peeked event and must take effect
208 /// immediately, which buffered events would defeat.
209 bypass_event_buffer: bool,
210
211 _marker: PhantomData<&'input ()>,
212}
213
214impl<'parser, 'input> FormatDeserializer<'parser, 'input, true> {
215 /// Create a new deserializer that can borrow strings from input.
216 pub fn new(parser: &'parser mut dyn FormatParser<'input>) -> Self {
217 Self::with_buffer_capacity(parser, DEFAULT_EVENT_BUFFER_SIZE)
218 }
219
220 /// Create a new deserializer with a custom buffer capacity.
221 pub fn with_buffer_capacity(
222 parser: &'parser mut dyn FormatParser<'input>,
223 buffer_capacity: usize,
224 ) -> Self {
225 let is_non_self_describing = !parser.is_self_describing();
226 let bypass_event_buffer = is_non_self_describing || parser.needs_container_hints();
227 Self {
228 parser,
229 last_span: Span { offset: 0, len: 0 },
230 event_buffer: VecDeque::with_capacity(buffer_capacity),
231 buffer_capacity,
232 is_non_self_describing,
233 bypass_event_buffer,
234 _marker: PhantomData,
235 }
236 }
237}
238
239impl<'parser, 'input> FormatDeserializer<'parser, 'input, false> {
240 /// Create a new deserializer that produces owned strings.
241 pub fn new_owned(parser: &'parser mut dyn FormatParser<'input>) -> Self {
242 Self::with_buffer_capacity_owned(parser, DEFAULT_EVENT_BUFFER_SIZE)
243 }
244
245 /// Create a new deserializer with a custom buffer capacity.
246 pub fn with_buffer_capacity_owned(
247 parser: &'parser mut dyn FormatParser<'input>,
248 buffer_capacity: usize,
249 ) -> Self {
250 let is_non_self_describing = !parser.is_self_describing();
251 let bypass_event_buffer = is_non_self_describing || parser.needs_container_hints();
252 Self {
253 parser,
254 last_span: Span { offset: 0, len: 0 },
255 event_buffer: VecDeque::with_capacity(buffer_capacity),
256 buffer_capacity,
257 is_non_self_describing,
258 bypass_event_buffer,
259 _marker: PhantomData,
260 }
261 }
262}
263
264impl<'parser, 'input, const BORROW: bool> FormatDeserializer<'parser, 'input, BORROW> {
265 /// Borrow the inner parser mutably.
266 pub fn parser_mut(&mut self) -> &mut dyn FormatParser<'input> {
267 self.parser
268 }
269
270 /// Save deserializer state (both parser position AND event buffer).
271 ///
272 /// This must be used instead of calling `parser.save()` directly, because
273 /// the deserializer buffers events from the parser. If we only save/restore
274 /// the parser position, events already in the buffer would be lost.
275 fn save(&mut self) -> DeserializerSavePoint<'input> {
276 DeserializerSavePoint {
277 parser_save_point: self.parser.save(),
278 event_buffer: self.event_buffer.clone(),
279 }
280 }
281
282 /// Restore deserializer state (both parser position AND event buffer).
283 fn restore(&mut self, save_point: DeserializerSavePoint<'input>) {
284 self.parser.restore(save_point.parser_save_point);
285 self.event_buffer = save_point.event_buffer;
286 }
287}
288
289impl<'parser, 'input> FormatDeserializer<'parser, 'input, true> {
290 /// Deserialize the next value in the stream into `T`, allowing borrowed strings.
291 pub fn deserialize<T>(&mut self) -> Result<T, DeserializeError>
292 where
293 T: Facet<'input>,
294 {
295 let wip = Partial::alloc_with_plan(cached_type_plan_arc::<T>()?)?;
296 let partial = self.deserialize_into(wip, MetaSource::FromEvents)?;
297 // SpanGuard must cover build() and materialize() which can fail with ReflectError.
298 // Created AFTER deserialize_into so last_span points to the final token.
299 let _guard = SpanGuard::new(self.last_span);
300 let heap_value = partial.build()?;
301 Ok(heap_value.materialize::<T>()?)
302 }
303
304 /// Deserialize the next value in the stream into `T` (for backward compatibility).
305 pub fn deserialize_root<T>(&mut self) -> Result<T, DeserializeError>
306 where
307 T: Facet<'input>,
308 {
309 self.deserialize()
310 }
311
312 /// Deserialize using deferred mode, allowing interleaved field initialization.
313 ///
314 /// This is required for formats like TOML that allow table reopening, where
315 /// fields of a nested struct may be set, then fields of a sibling, then more
316 /// fields of the original struct.
317 pub fn deserialize_deferred<T>(&mut self) -> Result<T, DeserializeError>
318 where
319 T: Facet<'input>,
320 {
321 let wip = Partial::alloc_with_plan(cached_type_plan_arc::<T>()?)?;
322 let wip = wip.begin_deferred()?;
323 let partial = self.deserialize_into(wip, MetaSource::FromEvents)?;
324
325 // SpanGuard must cover finish_deferred(), build() and materialize() which can fail with ReflectError.
326 // Created AFTER deserialize_into so last_span points to the final token.
327 let _guard = SpanGuard::new(self.last_span);
328 let partial = partial.finish_deferred()?;
329 let heap_value = partial.build()?;
330 Ok(heap_value.materialize::<T>()?)
331 }
332}
333
334impl<'parser, 'input> FormatDeserializer<'parser, 'input, false> {
335 /// Deserialize the next value in the stream into `T`, using owned strings.
336 pub fn deserialize<T>(&mut self) -> Result<T, DeserializeError>
337 where
338 T: Facet<'static>,
339 {
340 let wip = Partial::alloc_owned_with_plan(cached_type_plan_arc::<T>()?)?;
341 // SAFETY: alloc_owned_with_plan produces Partial<'static, false>, but deserialize_into
342 // expects 'input. Since BORROW=false means we never borrow from input anyway,
343 // this is safe.
344 #[allow(unsafe_code)]
345 let wip: Partial<'input, false> = unsafe { core::mem::transmute(wip) };
346
347 let partial = self.deserialize_into(wip, MetaSource::FromEvents)?;
348
349 // SpanGuard must cover build() and materialize() which can fail with ReflectError.
350 // Created AFTER deserialize_into so last_span points to the final token.
351 let _guard = SpanGuard::new(self.last_span);
352 let heap_value = partial.build()?;
353
354 // SAFETY: HeapValue<'input, false> contains no borrowed data because BORROW=false.
355 // The transmute only changes the phantom lifetime marker.
356 #[allow(unsafe_code)]
357 let heap_value: HeapValue<'static, false> = unsafe { core::mem::transmute(heap_value) };
358
359 Ok(heap_value.materialize::<T>()?)
360 }
361
362 /// Deserialize the next value in the stream into `T` (for backward compatibility).
363 pub fn deserialize_root<T>(&mut self) -> Result<T, DeserializeError>
364 where
365 T: Facet<'static>,
366 {
367 self.deserialize()
368 }
369
370 /// Deserialize using deferred mode, allowing interleaved field initialization.
371 ///
372 /// This is required for formats like TOML that allow table reopening, where
373 /// fields of a nested struct may be set, then fields of a sibling, then more
374 /// fields of the original struct.
375 pub fn deserialize_deferred<T>(&mut self) -> Result<T, DeserializeError>
376 where
377 T: Facet<'static>,
378 {
379 let wip = Partial::alloc_owned_with_plan(cached_type_plan_arc::<T>()?)?;
380 // SAFETY: alloc_owned_with_plan produces Partial<'static, false>, but deserialize_into
381 // expects 'input. Since BORROW=false means we never borrow from input anyway,
382 // this is safe.
383 #[allow(unsafe_code)]
384 let wip: Partial<'input, false> = unsafe { core::mem::transmute(wip) };
385 let wip = wip.begin_deferred()?;
386 let partial = self.deserialize_into(wip, MetaSource::FromEvents)?;
387
388 // SpanGuard must cover finish_deferred(), build() and materialize() which can fail with ReflectError.
389 // Created AFTER deserialize_into so last_span points to the final token.
390 let _guard = SpanGuard::new(self.last_span);
391 let partial = partial.finish_deferred()?;
392 let heap_value = partial.build()?;
393
394 // SAFETY: HeapValue<'input, false> contains no borrowed data because BORROW=false.
395 // The transmute only changes the phantom lifetime marker.
396 #[allow(unsafe_code)]
397 let heap_value: HeapValue<'static, false> = unsafe { core::mem::transmute(heap_value) };
398
399 Ok(heap_value.materialize::<T>()?)
400 }
401
402 /// Deserialize using an explicit source shape for parser hints.
403 ///
404 /// This is useful for non-self-describing formats like postcard where you need
405 /// to decode data that was serialized using a specific type, but you only have
406 /// the shape information at runtime (not the concrete type).
407 ///
408 /// The target type `T` should typically be a `DynamicValue` like `facet_value::Value`.
409 pub fn deserialize_with_shape<T>(
410 &mut self,
411 source_shape: &'static Shape,
412 ) -> Result<T, DeserializeError>
413 where
414 T: Facet<'static>,
415 {
416 let wip = Partial::alloc_owned_with_plan(cached_type_plan_arc::<T>()?)?;
417 // SAFETY: alloc_owned_with_plan produces Partial<'static, false>, but deserialize_into
418 // expects 'input. Since BORROW=false means we never borrow from input anyway,
419 // this is safe.
420 #[allow(unsafe_code)]
421 let wip: Partial<'input, false> = unsafe { core::mem::transmute(wip) };
422
423 let partial = self.deserialize_into_with_shape(wip, source_shape)?;
424
425 // SpanGuard must cover build() and materialize() which can fail with ReflectError.
426 // Created AFTER deserialize_into so last_span points to the final token.
427 let _guard = SpanGuard::new(self.last_span);
428 let heap_value = partial.build()?;
429
430 // SAFETY: HeapValue<'input, false> contains no borrowed data because BORROW=false.
431 // The transmute only changes the phantom lifetime marker.
432 #[allow(unsafe_code)]
433 let heap_value: HeapValue<'static, false> = unsafe { core::mem::transmute(heap_value) };
434
435 Ok(heap_value.materialize::<T>()?)
436 }
437}
438
439impl<'parser, 'input, const BORROW: bool> FormatDeserializer<'parser, 'input, BORROW> {
440 /// Refill the event buffer from the parser.
441 #[inline]
442 fn refill_buffer(&mut self) -> Result<(), ParseError> {
443 let _old_len = self.event_buffer.len();
444 self.parser
445 .next_events(&mut self.event_buffer, self.buffer_capacity)?;
446 let _new_len = self.event_buffer.len();
447 trace!("buffer refill {_old_len} => {_new_len} events");
448 Ok(())
449 }
450
451 /// Check if parser is non-self-describing.
452 #[inline(always)]
453 fn is_non_self_describing(&self) -> bool {
454 self.is_non_self_describing
455 }
456
457 /// Read the next event, returning an error if EOF is reached.
458 #[inline]
459 fn expect_event(
460 &mut self,
461 expected: &'static str,
462 ) -> Result<ParseEvent<'input>, DeserializeError> {
463 // Bypass buffering for non-self-describing and hint-dependent
464 // formats: hints clear or reclassify the parser's peeked event and
465 // must take effect immediately
466 if self.bypass_event_buffer {
467 let event = self.parser.next_event()?.ok_or_else(|| {
468 DeserializeErrorKind::UnexpectedEof { expected }.with_span(self.last_span)
469 })?;
470 trace!(?event, expected, "expect_event (direct): got event");
471 self.last_span = event.span;
472 return Ok(event);
473 }
474
475 // Refill if empty
476 if self.event_buffer.is_empty() {
477 self.refill_buffer()?;
478 }
479
480 let event = self.event_buffer.pop_front().ok_or_else(|| {
481 DeserializeErrorKind::UnexpectedEof { expected }.with_span(self.last_span)
482 })?;
483
484 trace!(?event, expected, "expect_event: got event");
485 self.last_span = event.span;
486 Ok(event)
487 }
488
489 /// Peek at the next event, returning an error if EOF is reached.
490 #[inline]
491 fn expect_peek(
492 &mut self,
493 expected: &'static str,
494 ) -> Result<ParseEvent<'input>, DeserializeError> {
495 self.peek_event_opt()?.ok_or_else(|| {
496 DeserializeErrorKind::UnexpectedEof { expected }.with_span(self.last_span)
497 })
498 }
499
500 /// Peek at the next event, returning None if EOF is reached.
501 #[inline]
502 fn peek_event_opt(&mut self) -> Result<Option<ParseEvent<'input>>, DeserializeError> {
503 // Bypass buffering for non-self-describing and hint-dependent formats
504 if self.bypass_event_buffer {
505 let event = self.parser.peek_event()?;
506 if let Some(ref _e) = event {
507 trace!(?_e, "peek_event_opt (direct): peeked event");
508 }
509 return Ok(event);
510 }
511
512 // Refill if empty
513 if self.event_buffer.is_empty() {
514 self.refill_buffer()?;
515 }
516
517 // FIXME: cloning bad for perf, obvs. can we borrow? can we stop cloningj?
518 let event = self.event_buffer.front().cloned();
519 if let Some(ref _e) = event {
520 trace!(?_e, "peeked event");
521 }
522 Ok(event)
523 }
524
525 /// Count buffered sequence items without consuming events.
526 ///
527 /// Scans the event buffer to count how many items exist at depth 0.
528 /// Returns the count found so far - this is a lower bound useful for
529 /// pre-reserving Vec capacity.
530 ///
531 /// If the full sequence is buffered (ends with `SequenceEnd`), this
532 /// returns the exact count. Otherwise it returns a partial count.
533 ///
534 /// In bypass mode (`bypass_event_buffer`) the buffer is always empty and
535 /// this returns 0 — capacity pre-reservation is simply unavailable there.
536 #[inline]
537 pub(crate) fn count_buffered_sequence_items(&self) -> usize {
538 use crate::ParseEventKind;
539
540 let mut count = 0usize;
541 let mut depth = 0i32;
542
543 for event in &self.event_buffer {
544 match &event.kind {
545 ParseEventKind::StructStart(_) | ParseEventKind::SequenceStart(_) => {
546 if depth == 0 {
547 // Starting a new item at depth 0
548 count += 1;
549 }
550 depth += 1;
551 }
552 ParseEventKind::StructEnd | ParseEventKind::SequenceEnd => {
553 depth -= 1;
554 if depth < 0 {
555 // Found the closing SequenceEnd for our list
556 return count;
557 }
558 }
559 ParseEventKind::Scalar(_) if depth == 0 => {
560 // Scalar at depth 0 is a list item
561 count += 1;
562 }
563 _ => {}
564 }
565 }
566
567 // Return partial count - still useful for reserve
568 count
569 }
570
571 /// Skip the current value using the buffer, returning start and end offsets.
572 #[inline]
573 fn skip_value_with_span(&mut self) -> Result<(usize, usize), DeserializeError> {
574 use crate::ParseEventKind;
575
576 // Peek to get the start offset
577 let first_event = self.expect_peek("value to skip")?;
578 let start_offset = first_event.span.offset as usize;
579 #[allow(unused_assignments)]
580 let mut end_offset = 0usize;
581
582 let mut depth = 0i32;
583 loop {
584 let event = self.expect_event("value to skip")?;
585 // Track the end of each event
586 end_offset = event.span.end();
587
588 match &event.kind {
589 ParseEventKind::StructStart(_) | ParseEventKind::SequenceStart(_) => {
590 depth += 1;
591 }
592 ParseEventKind::StructEnd | ParseEventKind::SequenceEnd => {
593 depth -= 1;
594 if depth <= 0 {
595 return Ok((start_offset, end_offset));
596 }
597 }
598 ParseEventKind::Scalar(_) if depth == 0 => {
599 return Ok((start_offset, end_offset));
600 }
601 _ => {}
602 }
603 }
604 }
605
606 /// Skip the current value using the buffer.
607 #[inline]
608 fn skip_value(&mut self) -> Result<(), DeserializeError> {
609 self.skip_value_with_span()?;
610 Ok(())
611 }
612
613 /// Capture the raw bytes of the current value without parsing it.
614 #[inline]
615 fn capture_raw(&mut self) -> Result<Option<&'input str>, DeserializeError> {
616 let Some(input) = self.parser.input() else {
617 // Parser doesn't provide raw input access
618 self.skip_value()?;
619 return Ok(None);
620 };
621
622 let (start, end) = self.skip_value_with_span()?;
623
624 // Slice the input
625 if end <= input.len() {
626 // SAFETY: We trust the parser's spans to be valid UTF-8 boundaries
627 let raw = core::str::from_utf8(&input[start..end]).map_err(|_| {
628 DeserializeErrorKind::InvalidValue {
629 message: "raw capture contains invalid UTF-8".into(),
630 }
631 .with_span(self.last_span)
632 })?;
633 Ok(Some(raw))
634 } else {
635 Ok(None)
636 }
637 }
638
639 /// Read the next event, returning None if EOF is reached.
640 #[inline]
641 fn next_event_opt(&mut self) -> Result<Option<ParseEvent<'input>>, DeserializeError> {
642 // Bypass buffering for non-self-describing and hint-dependent formats
643 if self.bypass_event_buffer {
644 let event = self.parser.next_event()?;
645 if let Some(ref event) = event {
646 self.last_span = event.span;
647 }
648 return Ok(event);
649 }
650
651 // Refill if empty
652 if self.event_buffer.is_empty() {
653 self.refill_buffer()?;
654 }
655
656 let Some(event) = self.event_buffer.pop_front() else {
657 return Ok(None);
658 };
659
660 self.last_span = event.span;
661 Ok(Some(event))
662 }
663
664 /// Attempt to solve which enum variant matches the input.
665 ///
666 /// This uses save/restore to read ahead and determine the variant without
667 /// consuming the events permanently. After this returns, the position
668 /// is restored so the actual deserialization can proceed.
669 pub(crate) fn solve_variant(
670 &mut self,
671 shape: &'static facet_core::Shape,
672 ) -> Result<Option<crate::SolveOutcome>, crate::SolveVariantError> {
673 let schema = Arc::new(Schema::build_auto(shape)?);
674 let mut solver = Solver::new(&schema);
675
676 // Save deserializer state (parser position AND event buffer)
677 let save_point = self.save();
678
679 let mut depth = 0i32;
680 let mut in_struct = false;
681 let mut expecting_value = false;
682 let mut pending_ambiguous: Option<(String, Vec<(&FieldInfo, u64)>)> = None;
683
684 let result = loop {
685 let event = self.next_event_opt().map_err(|e| {
686 crate::SolveVariantError::Parser(ParseError::new(
687 e.span.unwrap_or(self.last_span),
688 e.kind,
689 ))
690 })?;
691
692 let Some(event) = event else {
693 // EOF reached
694 self.restore(save_point);
695 return Ok(None);
696 };
697
698 if expecting_value && depth == 1 && in_struct {
699 expecting_value = false;
700 if let Some((key, fields)) = pending_ambiguous.take()
701 && let crate::ParseEventKind::Scalar(scalar) = &event.kind
702 {
703 let satisfied_shapes = select_best_ambiguous_scalar_shapes(scalar, &fields);
704 match solver.satisfy_at_path(&[key.as_str()], &satisfied_shapes) {
705 SatisfyResult::Solved(handle) => break Some(handle),
706 SatisfyResult::NoMatch => break None,
707 SatisfyResult::Continue => {}
708 // A solver result added since this match was written: keep
709 // scanning (the loop still terminates on struct end / EOF).
710 _ => {}
711 }
712 }
713 }
714
715 match event.kind {
716 crate::ParseEventKind::StructStart(_) => {
717 depth += 1;
718 if depth == 1 {
719 in_struct = true;
720 }
721 }
722 crate::ParseEventKind::StructEnd => {
723 depth -= 1;
724 if depth == 0 {
725 // Done with top-level struct
726 break None;
727 }
728 }
729 crate::ParseEventKind::SequenceStart(_) => {
730 depth += 1;
731 }
732 crate::ParseEventKind::SequenceEnd => {
733 depth -= 1;
734 }
735 crate::ParseEventKind::FieldKey(ref key) => {
736 if depth == 1 && in_struct {
737 // Top-level field - feed to solver
738 if let Some(name) = key.name() {
739 match solver.see_key(name.clone()) {
740 KeyResult::Solved(handle) => {
741 break Some(handle);
742 }
743 KeyResult::Ambiguous { fields } => {
744 pending_ambiguous = Some((name.to_string(), fields));
745 }
746 KeyResult::Unknown | KeyResult::Unambiguous { .. } => {
747 pending_ambiguous = None;
748 }
749 // A key result added since this match was written.
750 _ => {
751 pending_ambiguous = None;
752 }
753 }
754 }
755 expecting_value = true;
756 }
757 }
758 crate::ParseEventKind::Scalar(_)
759 | crate::ParseEventKind::OrderedField
760 | crate::ParseEventKind::VariantTag(_) => {
761 if expecting_value {
762 expecting_value = false;
763 }
764 }
765 }
766 };
767
768 // Restore deserializer state regardless of outcome
769 self.restore(save_point);
770
771 match result {
772 Some(handle) => {
773 let idx = handle.index();
774 Ok(Some(crate::SolveOutcome {
775 schema,
776 resolution_index: idx,
777 }))
778 }
779 None => Ok(None),
780 }
781 }
782
783 /// Make an error using the last span, the current path of the given wip.
784 fn mk_err(
785 &self,
786 wip: &Partial<'input, BORROW>,
787 kind: DeserializeErrorKind,
788 ) -> DeserializeError {
789 DeserializeError {
790 span: Some(self.last_span),
791 path: Some(wip.path()),
792 kind,
793 }
794 }
795}
796
797fn select_best_ambiguous_scalar_shapes(
798 scalar: &crate::ScalarValue<'_>,
799 fields: &[(&FieldInfo, u64)],
800) -> Vec<&'static Shape> {
801 let mut matches: Vec<(&'static Shape, u8, u64)> = Vec::new();
802 let mut best_quality: Option<u8> = None;
803
804 for (field, score) in fields {
805 let Some(quality) =
806 crate::deserializer::scalar_matches::scalar_match_quality(scalar, field.value_shape)
807 else {
808 continue;
809 };
810
811 match best_quality {
812 Some(best) if quality > best => continue,
813 Some(best) if quality < best => {
814 matches.clear();
815 best_quality = Some(quality);
816 }
817 None => {
818 best_quality = Some(quality);
819 }
820 _ => {}
821 }
822
823 if !matches.iter().any(|(shape, _, existing_score)| {
824 core::ptr::eq(*shape, field.value_shape) && *existing_score == *score
825 }) {
826 matches.push((field.value_shape, quality, *score));
827 }
828 }
829
830 let Some(best_quality) = best_quality else {
831 return Vec::new();
832 };
833
834 let best_specificity = matches
835 .iter()
836 .filter(|(_, quality, _)| *quality == best_quality)
837 .map(|(_, _, score)| *score)
838 .min()
839 .unwrap_or(u64::MAX);
840
841 matches
842 .into_iter()
843 .filter(|(_, quality, score)| *quality == best_quality && *score == best_specificity)
844 .map(|(shape, _, _)| shape)
845 .collect()
846}