Skip to main content

facet_format/
solver.rs

1extern crate alloc;
2
3use alloc::borrow::Cow;
4use alloc::sync::Arc;
5use core::fmt;
6use facet_core::Shape;
7
8use facet_solver::{KeyResult, Resolution, ResolutionHandle, Schema, Solver};
9
10use crate::{FormatParser, ParseError, ParseEventKind};
11
12/// High-level outcome from solving an untagged enum.
13pub struct SolveOutcome {
14    /// The schema that was used for solving
15    pub schema: Arc<Schema>,
16    /// Index of the chosen resolution in `schema.resolutions()`
17    pub resolution_index: usize,
18}
19
20/// Error when variant solving fails.
21#[derive(Debug)]
22pub enum SolveVariantError {
23    /// No variant matched the evidence.
24    NoMatch,
25    /// Parser error while reading events.
26    Parser(ParseError),
27    /// Schema construction error.
28    SchemaError(facet_solver::SchemaError),
29}
30
31impl SolveVariantError {
32    /// Wrap a parse error into [`SolveVariantError::Parser`].
33    pub const fn from_parser(e: ParseError) -> Self {
34        Self::Parser(e)
35    }
36}
37
38impl fmt::Display for SolveVariantError {
39    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::NoMatch => write!(f, "No variant matched"),
42            Self::Parser(e) => write!(f, "Parser error: {}", e),
43            Self::SchemaError(e) => write!(f, "Schema error: {}", e),
44        }
45    }
46}
47
48impl core::error::Error for SolveVariantError {}
49
50/// Attempt to solve which enum variant matches the input.
51///
52/// This uses save/restore to read ahead and determine the variant without
53/// consuming the events permanently. After this returns, the parser position
54/// is restored so the actual deserialization can proceed.
55///
56/// Returns `Ok(Some(_))` if a unique variant was found, `Ok(None)` if
57/// no variant matched, or `Err(_)` on error.
58pub fn solve_variant<'de>(
59    shape: &'static Shape,
60    parser: &mut dyn FormatParser<'de>,
61) -> Result<Option<SolveOutcome>, SolveVariantError> {
62    let schema = Arc::new(Schema::build_auto(shape)?);
63    let mut solver = Solver::new(&schema);
64
65    // Save position and start recording events
66    let save_point = parser.save();
67
68    let mut depth = 0i32;
69    let mut in_struct = false;
70    let mut expecting_value = false;
71
72    let result = loop {
73        let event = parser
74            .next_event()
75            .map_err(SolveVariantError::from_parser)?;
76
77        let Some(event) = event else {
78            // EOF reached
79            return Ok(None);
80        };
81
82        match event.kind {
83            ParseEventKind::StructStart(_) => {
84                depth += 1;
85                if depth == 1 {
86                    in_struct = true;
87                }
88            }
89            ParseEventKind::StructEnd => {
90                depth -= 1;
91                if depth == 0 {
92                    // Done with top-level struct
93                    break None;
94                }
95            }
96            ParseEventKind::SequenceStart(_) => {
97                depth += 1;
98            }
99            ParseEventKind::SequenceEnd => {
100                depth -= 1;
101            }
102            ParseEventKind::FieldKey(key) => {
103                if depth == 1 && in_struct {
104                    // Top-level field - feed to solver
105                    if let Some(name) = key.name().cloned()
106                        && let Some(handle) = handle_key(&mut solver, name)
107                    {
108                        break Some(handle);
109                    }
110                    expecting_value = true;
111                }
112            }
113            ParseEventKind::Scalar(_)
114            | ParseEventKind::OrderedField
115            | ParseEventKind::VariantTag(_) => {
116                if expecting_value {
117                    expecting_value = false;
118                }
119            }
120        }
121    };
122
123    // Restore position regardless of outcome
124    parser.restore(save_point);
125
126    match result {
127        Some(handle) => {
128            let idx = handle.index();
129            Ok(Some(SolveOutcome {
130                schema,
131                resolution_index: idx,
132            }))
133        }
134        None => Ok(None),
135    }
136}
137
138fn handle_key<'a>(solver: &mut Solver<'a>, name: Cow<'a, str>) -> Option<ResolutionHandle<'a>> {
139    match solver.see_key(name) {
140        KeyResult::Solved(handle) => Some(handle),
141        KeyResult::Unknown | KeyResult::Unambiguous { .. } | KeyResult::Ambiguous { .. } => None,
142    }
143}
144
145impl From<facet_solver::SchemaError> for SolveVariantError {
146    fn from(e: facet_solver::SchemaError) -> Self {
147        Self::SchemaError(e)
148    }
149}
150
151impl SolveOutcome {
152    /// Resolve the selected configuration reference.
153    pub fn resolution(&self) -> &Resolution {
154        &self.schema.resolutions()[self.resolution_index]
155    }
156}