use super::rows::OpRow;
use super::{DETACHED_EXIT, DRIFT_EXIT, PIPED_UNOBSERVED, SYNTHETIC_EXIT, YOG_STEP};
const SIGNAL_BASE: i32 = 128;
const SIGNAL_MAX: i32 = 64;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ExitKind {
Code(i32),
Signal(i32),
Unobserved,
Detached,
NeverSpawned,
StepFailed,
Drift,
}
impl ExitKind {
pub(crate) fn of(exit: i32, argv0: &str) -> Self {
match exit {
PIPED_UNOBSERVED => Self::Unobserved,
DETACHED_EXIT => Self::Detached,
SYNTHETIC_EXIT if argv0 == YOG_STEP => Self::StepFailed,
SYNTHETIC_EXIT => Self::NeverSpawned,
DRIFT_EXIT => Self::Drift,
c if c > SIGNAL_BASE && c - SIGNAL_BASE <= SIGNAL_MAX => Self::Signal(c - SIGNAL_BASE),
c => Self::Code(c),
}
}
pub(crate) fn label(self) -> String {
match self {
Self::Code(c) => format!("exit {c}"),
Self::Signal(n) => format!("killed by signal {n} (exit {})", SIGNAL_BASE + n),
Self::Unobserved => "ran; exit not observable".to_owned(),
Self::Detached => "detached — handed off, no exit to observe".to_owned(),
Self::NeverSpawned => "failed to spawn — never started".to_owned(),
Self::StepFailed => "step failed — nothing was spawned".to_owned(),
Self::Drift => "drift observation — not an attempted action".to_owned(),
}
}
}
impl OpRow {
fn kind(&self) -> ExitKind {
ExitKind::of(self.exit, self.argv.split(' ').next().unwrap_or_default())
}
pub fn exit_label(&self) -> String {
self.kind().label()
}
pub fn failed(&self) -> bool {
match self.kind() {
ExitKind::Code(0) | ExitKind::Unobserved | ExitKind::Drift => false,
ExitKind::Detached => !self.stderr.is_empty(),
_ => true,
}
}
pub(crate) fn detached(&self) -> bool {
matches!(self.kind(), ExitKind::Detached) && !self.failed()
}
pub(crate) fn detached_died(&self) -> bool {
matches!(self.kind(), ExitKind::Detached) && self.failed()
}
pub fn drift(&self) -> bool {
matches!(self.kind(), ExitKind::Drift)
}
}
#[cfg(test)]
mod tests;