use ostraka_core::gate::CheckRecord;
use ostraka_core::record::Event;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Phase {
Isolating,
Preparing,
Authoring,
Gating,
Reviewing,
}
impl Phase {
pub const ALL: [Phase; 5] = [
Phase::Isolating,
Phase::Preparing,
Phase::Authoring,
Phase::Gating,
Phase::Reviewing,
];
pub fn title(self) -> &'static str {
match self {
Phase::Isolating => "isolate",
Phase::Preparing => "prepare",
Phase::Authoring => "author",
Phase::Gating => "gate",
Phase::Reviewing => "review",
}
}
}
#[derive(Debug, Clone)]
pub enum Step {
Entered(Phase),
Said { phase: Phase, event: Event },
Checked(CheckRecord),
}
pub trait Watcher: Send {
fn saw(&mut self, step: Step);
}
pub struct Channel(pub std::sync::mpsc::Sender<Step>);
impl Watcher for Channel {
fn saw(&mut self, step: Step) {
let _ = self.0.send(step);
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::sync::mpsc;
#[test]
fn a_channel_watcher_passes_steps_through_in_order() {
let (tx, rx) = mpsc::channel();
let mut watcher = Channel(tx);
watcher.saw(Step::Entered(Phase::Authoring));
watcher.saw(Step::Entered(Phase::Gating));
let seen: Vec<Phase> = rx
.try_iter()
.filter_map(|s| match s {
Step::Entered(p) => Some(p),
_ => None,
})
.collect();
assert_eq!(seen, [Phase::Authoring, Phase::Gating]);
}
#[test]
fn a_watcher_whose_receiver_is_gone_does_not_fail_the_run() {
let (tx, rx) = mpsc::channel();
drop(rx);
let mut watcher = Channel(tx);
watcher.saw(Step::Entered(Phase::Isolating));
}
#[test]
fn every_phase_is_named() {
for phase in Phase::ALL {
assert!(!phase.title().is_empty(), "{phase:?}");
}
}
}