use std::sync::Arc;
use std::time::Instant;
use antecedent_core::ExecutionContext;
use antecedent_estimate::EffectEstimate;
use antecedent_identify::{IdentificationResult, IdentifiedEstimand};
use antecedent_validate::{PredictiveCheckReport, RefutationReport};
use crate::error::CausalError;
pub const STAGE_IDENTIFY: &str = "identify";
pub const STAGE_ESTIMATE_POINT: &str = "estimate_point";
pub const STAGE_UNCERTAINTY: &str = "uncertainty";
pub const STAGE_VALIDATE: &str = "validate";
#[derive(Clone, Debug)]
pub enum AnalysisStageEvent {
Identify {
identification: IdentificationResult,
estimand: IdentifiedEstimand,
},
Point {
estimate: EffectEstimate,
},
Uncertainty {
estimate: EffectEstimate,
},
Validate {
refutations: Vec<RefutationReport>,
predictive_checks: Vec<PredictiveCheckReport>,
},
}
impl AnalysisStageEvent {
#[must_use]
pub fn stage_id(&self) -> &'static str {
match self {
Self::Identify { .. } => STAGE_IDENTIFY,
Self::Point { .. } => STAGE_ESTIMATE_POINT,
Self::Uncertainty { .. } => STAGE_UNCERTAINTY,
Self::Validate { .. } => STAGE_VALIDATE,
}
}
}
pub trait StageResultSink: Send + Sync {
fn on_stage(&self, event: &AnalysisStageEvent);
}
#[derive(Debug)]
pub(crate) struct StageClock {
started: Instant,
stage_started: Instant,
timings: Vec<(Arc<str>, u64)>,
cancelled: bool,
}
impl StageClock {
pub(crate) fn new() -> Self {
let now = Instant::now();
Self { started: now, stage_started: now, timings: Vec::with_capacity(4), cancelled: false }
}
pub(crate) fn begin(
&mut self,
ctx: &ExecutionContext,
stage: &'static str,
fraction: f64,
) -> Result<(), CausalError> {
if ctx.cancellation.is_cancelled() {
self.cancelled = true;
return Err(CausalError::Cancelled { stage });
}
if let Some(p) = &ctx.progress {
p.report(fraction, stage);
}
self.stage_started = Instant::now();
Ok(())
}
pub(crate) fn finish(&mut self, stage: &'static str) {
let ns = u64::try_from(self.stage_started.elapsed().as_nanos()).unwrap_or(u64::MAX);
self.timings.push((Arc::from(stage), ns));
}
pub(crate) fn mark_cancelled(&mut self) {
self.cancelled = true;
}
#[must_use]
pub(crate) fn cancelled(&self) -> bool {
self.cancelled
}
#[must_use]
pub(crate) fn timings(&self) -> Vec<(Arc<str>, u64)> {
self.timings.clone()
}
#[must_use]
pub(crate) fn wall_time_ns(&self) -> u64 {
u64::try_from(self.started.elapsed().as_nanos()).unwrap_or(u64::MAX)
}
}
pub(crate) fn emit_stage(sink: Option<&Arc<dyn StageResultSink>>, event: &AnalysisStageEvent) {
if let Some(s) = sink {
s.on_stage(event);
}
}