facet_format/
solver.rs

1extern crate alloc;
2
3use alloc::sync::Arc;
4use core::fmt;
5
6use facet_solver::{KeyResult, Resolution, ResolutionHandle, Schema, Solver};
7
8use crate::{FieldEvidence, FormatParser, ProbeStream};
9
10/// High-level outcome from solving an untagged enum.
11pub struct SolveOutcome {
12    /// The schema that was used for solving
13    pub schema: Arc<Schema>,
14    /// Index of the chosen resolution in `schema.resolutions()`
15    pub resolution_index: usize,
16}
17
18/// Error when variant solving fails.
19#[derive(Debug)]
20pub enum SolveVariantError<E> {
21    /// No variant matched the evidence.
22    NoMatch,
23    /// Parser error while collecting evidence.
24    Parser(E),
25    /// Schema construction error.
26    SchemaError(facet_solver::SchemaError),
27}
28
29impl<E> SolveVariantError<E> {
30    /// Wrap a parser error into [`SolveVariantError::Parser`].
31    pub fn from_parser(e: E) -> Self {
32        Self::Parser(e)
33    }
34}
35
36impl<E: fmt::Display> fmt::Display for SolveVariantError<E> {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        match self {
39            Self::NoMatch => write!(f, "No variant matched"),
40            Self::Parser(e) => write!(f, "Parser error: {}", e),
41            Self::SchemaError(e) => write!(f, "Schema error: {}", e),
42        }
43    }
44}
45
46impl<E: fmt::Debug + fmt::Display> core::error::Error for SolveVariantError<E> {}
47
48/// Attempt to solve which enum variant matches the input.
49///
50/// Returns `Ok(Some(_))` if a unique variant was found, `Ok(None)` if
51/// no variant matched, or `Err(_)` on error.
52pub fn solve_variant<'de, P>(
53    shape: &'static facet_core::Shape,
54    parser: &mut P,
55) -> Result<Option<SolveOutcome>, SolveVariantError<P::Error>>
56where
57    P: FormatParser<'de>,
58{
59    let schema = Arc::new(Schema::build_auto(shape)?);
60    let mut solver = Solver::new(&schema);
61    let mut probe = parser
62        .begin_probe()
63        .map_err(SolveVariantError::from_parser)?;
64
65    while let Some(field) = probe.next().map_err(SolveVariantError::from_parser)? {
66        if let Some(handle) = handle_key(&mut solver, field) {
67            let idx = handle.index();
68            return Ok(Some(SolveOutcome {
69                schema,
70                resolution_index: idx,
71            }));
72        }
73    }
74
75    Ok(None)
76}
77
78fn handle_key<'a>(
79    solver: &mut Solver<'a>,
80    field: FieldEvidence<'a>,
81) -> Option<ResolutionHandle<'a>> {
82    let owned_name = field.name.into_owned();
83    match solver.see_key(owned_name) {
84        KeyResult::Solved(handle) => Some(handle),
85        KeyResult::Unknown | KeyResult::Unambiguous { .. } | KeyResult::Ambiguous { .. } => None,
86    }
87}
88
89impl<E> From<facet_solver::SchemaError> for SolveVariantError<E> {
90    fn from(e: facet_solver::SchemaError) -> Self {
91        Self::SchemaError(e)
92    }
93}
94impl SolveOutcome {
95    /// Resolve the selected configuration reference.
96    pub fn resolution(&self) -> &Resolution {
97        &self.schema.resolutions()[self.resolution_index]
98    }
99}