rustev_runtime/
progress.rs1use rustev_contract::{
3 evidence::StepStatus,
4 judgment::{Derivation, Unresolved},
5};
6use std::{
7 panic::{AssertUnwindSafe, catch_unwind},
8 sync::atomic::{AtomicU64, Ordering},
9};
10
11#[derive(Debug, Clone, PartialEq)]
13pub struct StepProgress {
14 pub step_id: String,
15 pub instance_ids: Vec<String>,
16 pub outcome: Result<(), Unresolved>,
17 pub derivation: Derivation,
18}
19
20pub trait ProgressObserver: Send + Sync {
24 fn admitted(&self) {}
26 fn step(&self, progress: StepProgress);
27}
28
29pub(crate) struct Observing<'a> {
30 pub observer: &'a dyn ProgressObserver,
31 pub panics: &'a AtomicU64,
32}
33impl Observing<'_> {
34 pub fn call(&self, f: impl FnOnce(&dyn ProgressObserver)) {
35 if catch_unwind(AssertUnwindSafe(|| f(self.observer))).is_err() {
36 self.panics.fetch_add(1, Ordering::Relaxed);
37 }
38 }
39 pub fn remaining(
40 &self,
41 evidence: &rustev_contract::evidence::EvidenceRecord,
42 requests: &[rustev_contract::run::RequestRecord],
43 plan: &rustev_contract::plan::Plan,
44 ) {
45 for step in &evidence.steps {
46 if requests
48 .iter()
49 .any(|r| r.step == step.step && r.instance == step.instance)
50 {
51 continue;
52 }
53 let (outcome, derivation) = match &step.status {
54 StepStatus::Skipped { .. } => continue,
55 StepStatus::Resolved { derivation, .. } => (Ok(()), *derivation),
56 StepStatus::Unresolved(reason) => (
59 Err(reason.clone()),
60 plan.steps
61 .iter()
62 .find(|s| s.id == step.step)
63 .expect("recorded step belongs to plan")
64 .derivation,
65 ),
66 };
67 self.call(|o| {
68 o.step(StepProgress {
69 step_id: step.step.clone(),
70 instance_ids: step.instance.clone(),
71 outcome,
72 derivation,
73 })
74 });
75 }
76 }
77}