extern crate alloc;
use alloc::string::String;
use crate::result::{Exploitability, MeasurementQuality};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum OutcomeType {
Pass = 0,
Fail = 1,
Inconclusive = 2,
ThresholdElevated = 3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[repr(u8)]
pub enum InconclusiveReasonKind {
#[default]
None = 0,
DataTooNoisy = 1,
NotLearning = 2,
WouldTakeTooLong = 3,
TimeBudgetExceeded = 4,
SampleBudgetExceeded = 5,
ConditionsChanged = 6,
ThresholdElevated = 7,
}
#[derive(Debug, Clone)]
pub struct PosteriorSummary {
pub max_effect_ns: f64,
pub ci_low_ns: f64,
pub ci_high_ns: f64,
pub leak_probability: f64,
pub n: usize,
pub lambda_mean: f64,
pub lambda_mixing_ok: bool,
pub kappa_mean: f64,
pub kappa_cv: f64,
pub kappa_ess: f64,
pub kappa_mixing_ok: bool,
}
impl PosteriorSummary {
pub fn total_effect_ns(&self) -> f64 {
self.max_effect_ns
}
pub fn measurement_quality(&self) -> MeasurementQuality {
let ci_width = self.ci_high_ns - self.ci_low_ns;
MeasurementQuality::from_mde_ns(ci_width / 2.0)
}
pub fn exploitability(&self) -> Exploitability {
Exploitability::from_effect_ns(self.max_effect_ns)
}
}
#[derive(Debug, Clone)]
pub struct CalibrationSummary {
pub block_length: usize,
pub calibration_samples: usize,
pub discrete_mode: bool,
pub timer_resolution_ns: f64,
pub theta_ns: f64,
pub theta_eff: f64,
pub theta_floor_initial: f64,
pub theta_tick: f64,
pub mde_ns: f64,
pub samples_per_second: f64,
}
#[derive(Debug, Clone)]
pub struct EffectSummary {
pub max_effect_ns: f64,
pub ci_low_ns: f64,
pub ci_high_ns: f64,
}
impl EffectSummary {
pub fn total_effect_ns(&self) -> f64 {
self.max_effect_ns
}
}
impl Default for EffectSummary {
fn default() -> Self {
Self {
max_effect_ns: 0.0,
ci_low_ns: 0.0,
ci_high_ns: 0.0,
}
}
}
#[derive(Debug, Clone)]
pub struct DiagnosticsSummary {
pub dependence_length: usize,
pub effective_sample_size: usize,
pub stationarity_ratio: f64,
pub stationarity_ok: bool,
pub discrete_mode: bool,
pub timer_resolution_ns: f64,
pub lambda_mean: f64,
pub lambda_mixing_ok: bool,
pub kappa_mean: f64,
pub kappa_cv: f64,
pub kappa_ess: f64,
pub kappa_mixing_ok: bool,
}
impl Default for DiagnosticsSummary {
fn default() -> Self {
Self {
dependence_length: 0,
effective_sample_size: 0,
stationarity_ratio: 1.0,
stationarity_ok: true,
discrete_mode: false,
timer_resolution_ns: 0.0,
lambda_mean: 1.0,
lambda_mixing_ok: true,
kappa_mean: 1.0,
kappa_cv: 0.0,
kappa_ess: 0.0,
kappa_mixing_ok: true,
}
}
}
#[derive(Debug, Clone)]
pub struct OutcomeSummary {
pub outcome_type: OutcomeType,
pub leak_probability: f64,
pub samples_per_class: usize,
pub elapsed_secs: f64,
pub effect: EffectSummary,
pub quality: MeasurementQuality,
pub exploitability: Exploitability,
pub inconclusive_reason: InconclusiveReasonKind,
pub recommendation: String,
pub theta_user: f64,
pub theta_eff: f64,
pub theta_floor: f64,
pub theta_tick: f64,
pub achievable_at_max: bool,
pub diagnostics: DiagnosticsSummary,
pub mde_ns: f64,
}
impl OutcomeSummary {
pub fn is_conclusive(&self) -> bool {
matches!(self.outcome_type, OutcomeType::Pass | OutcomeType::Fail)
}
pub fn is_leak_detected(&self) -> bool {
matches!(self.outcome_type, OutcomeType::Fail)
}
}