Skip to main content

rustev_core/
sem.rs

1//! Semantic step values as the core holds them after validation.
2
3use std::collections::BTreeMap;
4
5use rustev_contract::judgment::Unresolved;
6
7use crate::kinds::{CalibratedProbability, Distribution, ModelScore, OrdinalLevel, SelectedLabel};
8
9/// The value kind a semantic step produces once bound (spec 002, 3.9.3).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub enum SemKind {
12    Label,
13    Distribution,
14    Calibrated,
15    /// An ordinal level; `true` when it carries a distribution over levels.
16    Ordinal(bool),
17    Scores,
18}
19
20impl SemKind {
21    pub fn name(self) -> &'static str {
22        match self {
23            SemKind::Label => "selected_label",
24            SemKind::Distribution => "distribution",
25            SemKind::Calibrated => "calibrated_probability",
26            SemKind::Ordinal(true) => "ordinal_level(distribution)",
27            SemKind::Ordinal(false) => "ordinal_level(label)",
28            SemKind::Scores => "model_score",
29        }
30    }
31
32    pub fn has_mass(self) -> bool {
33        matches!(self, SemKind::Distribution | SemKind::Calibrated)
34    }
35}
36
37/// One validated semantic value.
38#[derive(Debug, Clone, PartialEq)]
39pub enum SemValue {
40    /// Opaque screening result, never an authored label.
41    Screen {
42        blocked: bool,
43        categories: Vec<String>,
44    },
45    /// Empty text requires no backend call.
46    ScreenEmpty,
47    Label(SelectedLabel),
48    Distribution(Distribution),
49    Calibrated(CalibratedProbability),
50    Ordinal(OrdinalLevel),
51    Scores(Vec<ModelScore>),
52}
53
54impl SemValue {
55    /// Mass of an option, when the kind has mass.
56    pub fn mass(&self, option: &str) -> Option<f64> {
57        match self {
58            SemValue::Distribution(d) => d.mass(option),
59            SemValue::Calibrated(c) => c.mass(option),
60            _ => None,
61        }
62    }
63
64    /// The top label and its mass (none for a label).
65    pub fn top(&self) -> Option<(String, Option<f64>)> {
66        match self {
67            SemValue::Label(l) => Some((l.label().to_string(), None)),
68            SemValue::Distribution(d) => Some((d.top().0.to_string(), Some(d.top().1))),
69            SemValue::Calibrated(c) => Some((c.top().0.to_string(), Some(c.top().1))),
70            SemValue::Ordinal(o) => Some((o.top().to_string(), None)),
71            SemValue::Scores(_) | SemValue::Screen { .. } | SemValue::ScreenEmpty => None,
72        }
73    }
74}
75
76/// A semantic step's instances, keyed by instance key (empty for a step
77/// without fan-out).
78pub type SemInstances = BTreeMap<Vec<String>, Result<SemValue, Unresolved>>;