#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum OperatorSignal {
Hup,
Int,
Quit,
Term,
Usr1,
Usr2,
Winch,
Cont,
Kill,
}
impl OperatorSignal {
pub const ACCEPTED: [&'static str; 9] = [
"SIGHUP", "SIGINT", "SIGQUIT", "SIGTERM", "SIGUSR1", "SIGUSR2", "SIGWINCH", "SIGCONT",
"SIGKILL",
];
#[must_use]
pub fn parse(name: &str) -> Option<Self> {
match name.to_ascii_uppercase().as_str() {
"SIGHUP" | "HUP" => Some(Self::Hup),
"SIGINT" | "INT" => Some(Self::Int),
"SIGQUIT" | "QUIT" => Some(Self::Quit),
"SIGTERM" | "TERM" => Some(Self::Term),
"SIGUSR1" | "USR1" => Some(Self::Usr1),
"SIGUSR2" | "USR2" => Some(Self::Usr2),
"SIGWINCH" | "WINCH" => Some(Self::Winch),
"SIGCONT" | "CONT" => Some(Self::Cont),
"SIGKILL" | "KILL" => Some(Self::Kill),
_ => None,
}
}
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
Self::Hup => "SIGHUP",
Self::Int => "SIGINT",
Self::Quit => "SIGQUIT",
Self::Term => "SIGTERM",
Self::Usr1 => "SIGUSR1",
Self::Usr2 => "SIGUSR2",
Self::Winch => "SIGWINCH",
Self::Cont => "SIGCONT",
Self::Kill => "SIGKILL",
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn every_accepted_name_round_trips_through_parse() {
for name in OperatorSignal::ACCEPTED {
let parsed = OperatorSignal::parse(name)
.unwrap_or_else(|| panic!("`{name}` is advertised but not parsed"));
assert_eq!(parsed.as_str(), name);
}
}
#[test]
fn the_prefix_and_the_case_are_both_optional() {
assert_eq!(OperatorSignal::parse("hup"), Some(OperatorSignal::Hup));
assert_eq!(OperatorSignal::parse("SigUsr1"), Some(OperatorSignal::Usr1));
assert_eq!(OperatorSignal::parse("WINCH"), Some(OperatorSignal::Winch));
}
#[test]
fn sigstop_is_refused_because_the_shepherd_could_not_report_it() {
assert_eq!(OperatorSignal::parse("SIGSTOP"), None);
assert_eq!(OperatorSignal::parse("stop"), None);
}
#[test]
fn a_name_outside_the_table_does_not_parse() {
assert_eq!(OperatorSignal::parse("SIGSEGV"), None);
assert_eq!(OperatorSignal::parse(""), None);
assert_eq!(OperatorSignal::parse("9"), None);
}
#[test]
fn every_kill_signal_name_is_also_an_operator_signal() {
for name in crate::config::KillSignal::ACCEPTED {
assert!(
OperatorSignal::parse(name).is_some(),
"`{name}` is a kill_signal but not an operator signal"
);
}
}
}