extern crate alloc;
use alloc::borrow::Cow;
use alloc::sync::Arc;
use core::fmt;
use facet_core::Shape;
use facet_solver::{KeyResult, Resolution, ResolutionHandle, Schema, Solver};
use crate::{FormatParser, ParseError, ParseEventKind};
pub struct SolveOutcome {
pub schema: Arc<Schema>,
pub resolution_index: usize,
}
#[derive(Debug)]
pub enum SolveVariantError {
NoMatch,
Parser(ParseError),
SchemaError(facet_solver::SchemaError),
}
impl SolveVariantError {
pub const fn from_parser(e: ParseError) -> Self {
Self::Parser(e)
}
}
impl fmt::Display for SolveVariantError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NoMatch => write!(f, "No variant matched"),
Self::Parser(e) => write!(f, "Parser error: {}", e),
Self::SchemaError(e) => write!(f, "Schema error: {}", e),
}
}
}
impl core::error::Error for SolveVariantError {}
pub fn solve_variant<'de>(
shape: &'static Shape,
parser: &mut dyn FormatParser<'de>,
) -> Result<Option<SolveOutcome>, SolveVariantError> {
let schema = Arc::new(Schema::build_auto(shape)?);
let mut solver = Solver::new(&schema);
let save_point = parser.save();
let mut depth = 0i32;
let mut in_struct = false;
let mut expecting_value = false;
let result = loop {
let event = parser
.next_event()
.map_err(SolveVariantError::from_parser)?;
let Some(event) = event else {
return Ok(None);
};
match event.kind {
ParseEventKind::StructStart(_) => {
depth += 1;
if depth == 1 {
in_struct = true;
}
}
ParseEventKind::StructEnd => {
depth -= 1;
if depth == 0 {
break None;
}
}
ParseEventKind::SequenceStart(_) => {
depth += 1;
}
ParseEventKind::SequenceEnd => {
depth -= 1;
}
ParseEventKind::FieldKey(key) => {
if depth == 1 && in_struct {
if let Some(name) = key.name().cloned()
&& let Some(handle) = handle_key(&mut solver, name)
{
break Some(handle);
}
expecting_value = true;
}
}
ParseEventKind::Scalar(_)
| ParseEventKind::OrderedField
| ParseEventKind::VariantTag(_) => {
if expecting_value {
expecting_value = false;
}
}
}
};
parser.restore(save_point);
match result {
Some(handle) => {
let idx = handle.index();
Ok(Some(SolveOutcome {
schema,
resolution_index: idx,
}))
}
None => Ok(None),
}
}
fn handle_key<'a>(solver: &mut Solver<'a>, name: Cow<'a, str>) -> Option<ResolutionHandle<'a>> {
match solver.see_key(name) {
KeyResult::Solved(handle) => Some(handle),
KeyResult::Unknown | KeyResult::Unambiguous { .. } | KeyResult::Ambiguous { .. } => None,
}
}
impl From<facet_solver::SchemaError> for SolveVariantError {
fn from(e: facet_solver::SchemaError) -> Self {
Self::SchemaError(e)
}
}
impl SolveOutcome {
pub fn resolution(&self) -> &Resolution {
&self.schema.resolutions()[self.resolution_index]
}
}