Solver

Struct Solver 

Source
pub struct Solver<'a> { /* private fields */ }
Expand description

State machine solver for lazy value-based disambiguation.

This solver only requests value inspection when candidates disagree on type. For keys where all candidates expect the same type, the deserializer can skip detailed value analysis.

§Example

use facet::Facet;
use facet_solver::{Schema, Solver, KeyResult, SatisfyResult};

#[derive(Facet)]
#[repr(u8)]
enum NumericValue {
    Small(u8),
    Large(u16),
}

#[derive(Facet)]
struct Container {
    #[facet(flatten)]
    value: NumericValue,
}

let schema = Schema::build(Container::SHAPE).unwrap();
let mut solver = Solver::new(&schema);

// The field "0" has different types (u8 vs u16) - solver needs disambiguation
match solver.see_key("0") {
    KeyResult::Ambiguous { fields } => {
        // Deserializer sees value "1000", checks which fields can accept it
        // u8 can't hold 1000, u16 can - so only report the u16 field
        // Fields come with specificity scores - lower = more specific
        let satisfied: Vec<_> = fields.iter()
            .filter(|(f, _score)| {
                // deserializer's logic: can this value parse as this field's type?
                f.value_shape.type_identifier == "u16"
            })
            .map(|(f, _)| *f)
            .collect();

        match solver.satisfy(&satisfied) {
            SatisfyResult::Solved(config) => {
                assert!(config.resolution().describe().contains("Large"));
            }
            _ => panic!("expected solved"),
        }
    }
    _ => panic!("expected Ambiguous"),
}

Implementations§

Source§

impl<'a> Solver<'a>

Source

pub fn new(schema: &'a Schema) -> Self

Create a new solver from a schema.

Source

pub fn see_key(&mut self, key: impl Into<Cow<'a, str>>) -> KeyResult<'a>

Report a key. Returns what to do next.

  • Unambiguous: All candidates agree on the type - parse directly
  • Ambiguous: Types differ - check which fields the value can satisfy
  • Solved: Disambiguated to one config
  • Unknown: Key not found in any candidate

Accepts both borrowed (&str) and owned (String) keys via Cow.

Source

pub fn satisfy(&mut self, satisfied_fields: &[&FieldInfo]) -> SatisfyResult<'a>

Report which fields the value can satisfy after Ambiguous result.

The deserializer should pass the subset of fields (from the Ambiguous result) that the actual value can be parsed into.

Source

pub fn satisfy_shapes( &mut self, satisfied_shapes: &[&'static Shape], ) -> SatisfyResult<'a>

Report which shapes the value can satisfy after Ambiguous result from probe_key.

This is the shape-based version of satisfy, used when disambiguating by nested field types. The deserializer should pass the shapes that the actual value can be parsed into.

§Example
use facet::Facet;
use facet_solver::{Schema, Solver, KeyResult, SatisfyResult};

#[derive(Facet)]
struct SmallPayload { value: u8 }

#[derive(Facet)]
struct LargePayload { value: u16 }

#[derive(Facet)]
#[repr(u8)]
enum PayloadKind {
    Small { payload: SmallPayload },
    Large { payload: LargePayload },
}

#[derive(Facet)]
struct Container {
    #[facet(flatten)]
    inner: PayloadKind,
}

let schema = Schema::build(Container::SHAPE).unwrap();
let mut solver = Solver::new(&schema);

// Report nested key
solver.probe_key(&[], "payload");

// At payload.value, value is 1000 - doesn't fit u8
// Get shapes at this path
let shapes = solver.get_shapes_at_path(&["payload", "value"]);
// Filter to shapes that can hold 1000
let works: Vec<_> = shapes.iter()
    .filter(|s| s.type_identifier == "u16")
    .copied()
    .collect();
solver.satisfy_shapes(&works);
Source

pub fn get_shapes_at_path(&self, path: &[&str]) -> Vec<&'static Shape>

Get the shapes at a nested path across all remaining candidates.

This is useful when you have an Ambiguous result from probe_key and need to know what types are possible at that path.

Source

pub fn satisfy_at_path( &mut self, path: &[&str], satisfied_shapes: &[&'static Shape], ) -> SatisfyResult<'a>

Report which shapes at a nested path the value can satisfy.

This is the path-aware version of satisfy_shapes, used when disambiguating by nested field types after probe_key.

  • path: The full path to the field (e.g., ["payload", "value"])
  • satisfied_shapes: The shapes that the value can be parsed into
Source

pub fn candidates(&self) -> Vec<ResolutionHandle<'a>>

Get the current candidate resolutions.

Source

pub fn seen_keys(&self) -> &BTreeSet<Cow<'a, str>>

Get the seen keys.

Source

pub fn hint_variant(&mut self, variant_name: &str) -> bool

Hint that a specific enum variant should be selected.

This filters the candidates to only those resolutions where at least one variant selection has the given variant name. This is useful for explicit type disambiguation via annotations (e.g., KDL type annotations like (Http)node).

Returns true if at least one candidate remains after filtering, false if no candidates match the variant name (in which case candidates are unchanged).

§Example
use facet::Facet;
use facet_solver::{Schema, Solver};

#[derive(Facet)]
struct HttpSource { url: String }

#[derive(Facet)]
struct GitSource { url: String, branch: String }

#[derive(Facet)]
#[repr(u8)]
enum SourceKind {
    Http(HttpSource),
    Git(GitSource),
}

#[derive(Facet)]
struct Source {
    #[facet(flatten)]
    kind: SourceKind,
}

let schema = Schema::build(Source::SHAPE).unwrap();
let mut solver = Solver::new(&schema);

// Without hint, both variants are candidates
assert_eq!(solver.candidates().len(), 2);

// Hint at Http variant
assert!(solver.hint_variant("Http"));
assert_eq!(solver.candidates().len(), 1);
Source

pub fn mark_seen(&mut self, key: impl Into<Cow<'a, str>>)

Mark a key as seen without filtering candidates.

This is useful when the key is known to be present through means other than parsing (e.g., type annotations). Call this after hint_variant to mark the variant name as seen so that finish() doesn’t report it as missing.

Source

pub fn probe_key(&mut self, path: &[&str], key: &str) -> KeyResult<'a>

Report a key at a nested path. Returns what to do next.

This is the depth-aware version of see_key. Use this when probing nested structures where disambiguation might require looking inside objects.

  • path: The ancestor keys (e.g., ["payload"] when inside a payload object)
  • key: The key found at this level (e.g., "value")
§Example
use facet::Facet;
use facet_solver::{Schema, Solver, KeyResult};

#[derive(Facet)]
struct SmallPayload { value: u8 }

#[derive(Facet)]
struct LargePayload { value: u16 }

#[derive(Facet)]
#[repr(u8)]
enum PayloadKind {
    Small { payload: SmallPayload },
    Large { payload: LargePayload },
}

#[derive(Facet)]
struct Container {
    #[facet(flatten)]
    inner: PayloadKind,
}

let schema = Schema::build(Container::SHAPE).unwrap();
let mut solver = Solver::new(&schema);

// "payload" exists in both - keep going
solver.probe_key(&[], "payload");

// "value" inside payload - both have it but different types!
match solver.probe_key(&["payload"], "value") {
    KeyResult::Ambiguous { fields } => {
        // fields is Vec<(&FieldInfo, u64)> - field + specificity score
        // Deserializer checks: 1000 fits u16 but not u8
        // When multiple match, pick the one with lowest score (most specific)
    }
    _ => {}
}
Source

pub fn finish(self) -> Result<ResolutionHandle<'a>, SolverError>

Finish solving. Call this after all keys have been processed.

This method is necessary because key-based filtering alone cannot disambiguate when one variant’s required fields are a subset of another’s.

§Why not just use see_key() results?

see_key() returns Solved when a key excludes candidates down to one. But when the input is a valid subset of multiple variants, no key excludes anything — you need finish() to check which candidates have all their required fields satisfied.

§Example
enum Source {
    Http { url: String },                  // required: url
    Git { url: String, branch: String },   // required: url, branch
}
Inputsee_key behaviorResolution
{ "url", "branch" }branch excludes Http → candidates = 1Early Solved(Git)
{ "url" }both have url → candidates = 2finish()Http

In the second case, no key ever excludes a candidate. Only finish() can determine that Git is missing its required branch field, leaving Http as the sole viable configuration.

Trait Implementations§

Source§

impl<'a> Debug for Solver<'a>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a> Freeze for Solver<'a>

§

impl<'a> RefUnwindSafe for Solver<'a>

§

impl<'a> Send for Solver<'a>

§

impl<'a> Sync for Solver<'a>

§

impl<'a> Unpin for Solver<'a>

§

impl<'a> UnwindSafe for Solver<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<D> OwoColorize for D

Source§

fn fg<C>(&self) -> FgColorDisplay<'_, C, Self>
where C: Color,

Set the foreground color generically Read more
Source§

fn bg<C>(&self) -> BgColorDisplay<'_, C, Self>
where C: Color,

Set the background color generically. Read more
Source§

fn black(&self) -> FgColorDisplay<'_, Black, Self>

Change the foreground color to black
Source§

fn on_black(&self) -> BgColorDisplay<'_, Black, Self>

Change the background color to black
Source§

fn red(&self) -> FgColorDisplay<'_, Red, Self>

Change the foreground color to red
Source§

fn on_red(&self) -> BgColorDisplay<'_, Red, Self>

Change the background color to red
Source§

fn green(&self) -> FgColorDisplay<'_, Green, Self>

Change the foreground color to green
Source§

fn on_green(&self) -> BgColorDisplay<'_, Green, Self>

Change the background color to green
Source§

fn yellow(&self) -> FgColorDisplay<'_, Yellow, Self>

Change the foreground color to yellow
Source§

fn on_yellow(&self) -> BgColorDisplay<'_, Yellow, Self>

Change the background color to yellow
Source§

fn blue(&self) -> FgColorDisplay<'_, Blue, Self>

Change the foreground color to blue
Source§

fn on_blue(&self) -> BgColorDisplay<'_, Blue, Self>

Change the background color to blue
Source§

fn magenta(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to magenta
Source§

fn on_magenta(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to magenta
Source§

fn purple(&self) -> FgColorDisplay<'_, Magenta, Self>

Change the foreground color to purple
Source§

fn on_purple(&self) -> BgColorDisplay<'_, Magenta, Self>

Change the background color to purple
Source§

fn cyan(&self) -> FgColorDisplay<'_, Cyan, Self>

Change the foreground color to cyan
Source§

fn on_cyan(&self) -> BgColorDisplay<'_, Cyan, Self>

Change the background color to cyan
Source§

fn white(&self) -> FgColorDisplay<'_, White, Self>

Change the foreground color to white
Source§

fn on_white(&self) -> BgColorDisplay<'_, White, Self>

Change the background color to white
Source§

fn default_color(&self) -> FgColorDisplay<'_, Default, Self>

Change the foreground color to the terminal default
Source§

fn on_default_color(&self) -> BgColorDisplay<'_, Default, Self>

Change the background color to the terminal default
Source§

fn bright_black(&self) -> FgColorDisplay<'_, BrightBlack, Self>

Change the foreground color to bright black
Source§

fn on_bright_black(&self) -> BgColorDisplay<'_, BrightBlack, Self>

Change the background color to bright black
Source§

fn bright_red(&self) -> FgColorDisplay<'_, BrightRed, Self>

Change the foreground color to bright red
Source§

fn on_bright_red(&self) -> BgColorDisplay<'_, BrightRed, Self>

Change the background color to bright red
Source§

fn bright_green(&self) -> FgColorDisplay<'_, BrightGreen, Self>

Change the foreground color to bright green
Source§

fn on_bright_green(&self) -> BgColorDisplay<'_, BrightGreen, Self>

Change the background color to bright green
Source§

fn bright_yellow(&self) -> FgColorDisplay<'_, BrightYellow, Self>

Change the foreground color to bright yellow
Source§

fn on_bright_yellow(&self) -> BgColorDisplay<'_, BrightYellow, Self>

Change the background color to bright yellow
Source§

fn bright_blue(&self) -> FgColorDisplay<'_, BrightBlue, Self>

Change the foreground color to bright blue
Source§

fn on_bright_blue(&self) -> BgColorDisplay<'_, BrightBlue, Self>

Change the background color to bright blue
Source§

fn bright_magenta(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright magenta
Source§

fn on_bright_magenta(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright magenta
Source§

fn bright_purple(&self) -> FgColorDisplay<'_, BrightMagenta, Self>

Change the foreground color to bright purple
Source§

fn on_bright_purple(&self) -> BgColorDisplay<'_, BrightMagenta, Self>

Change the background color to bright purple
Source§

fn bright_cyan(&self) -> FgColorDisplay<'_, BrightCyan, Self>

Change the foreground color to bright cyan
Source§

fn on_bright_cyan(&self) -> BgColorDisplay<'_, BrightCyan, Self>

Change the background color to bright cyan
Source§

fn bright_white(&self) -> FgColorDisplay<'_, BrightWhite, Self>

Change the foreground color to bright white
Source§

fn on_bright_white(&self) -> BgColorDisplay<'_, BrightWhite, Self>

Change the background color to bright white
Source§

fn bold(&self) -> BoldDisplay<'_, Self>

Make the text bold
Source§

fn dimmed(&self) -> DimDisplay<'_, Self>

Make the text dim
Source§

fn italic(&self) -> ItalicDisplay<'_, Self>

Make the text italicized
Source§

fn underline(&self) -> UnderlineDisplay<'_, Self>

Make the text underlined
Make the text blink
Make the text blink (but fast!)
Source§

fn reversed(&self) -> ReversedDisplay<'_, Self>

Swap the foreground and background colors
Source§

fn hidden(&self) -> HiddenDisplay<'_, Self>

Hide the text
Source§

fn strikethrough(&self) -> StrikeThroughDisplay<'_, Self>

Cross out the text
Source§

fn color<Color>(&self, color: Color) -> FgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the foreground color at runtime. Only use if you do not know which color will be used at compile-time. If the color is constant, use either OwoColorize::fg or a color-specific method, such as OwoColorize::green, Read more
Source§

fn on_color<Color>(&self, color: Color) -> BgDynColorDisplay<'_, Color, Self>
where Color: DynColor,

Set the background color at runtime. Only use if you do not know what color to use at compile-time. If the color is constant, use either OwoColorize::bg or a color-specific method, such as OwoColorize::on_yellow, Read more
Source§

fn fg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> FgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the foreground color to a specific RGB value.
Source§

fn bg_rgb<const R: u8, const G: u8, const B: u8>( &self, ) -> BgColorDisplay<'_, CustomColor<R, G, B>, Self>

Set the background color to a specific RGB value.
Source§

fn truecolor(&self, r: u8, g: u8, b: u8) -> FgDynColorDisplay<'_, Rgb, Self>

Sets the foreground color to an RGB value.
Source§

fn on_truecolor(&self, r: u8, g: u8, b: u8) -> BgDynColorDisplay<'_, Rgb, Self>

Sets the background color to an RGB value.
Source§

fn style(&self, style: Style) -> Styled<&Self>

Apply a runtime-determined style
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.