#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Signal {
Term,
Kill,
Int,
Hup,
Quit,
Usr1,
Usr2,
Other(i32),
}
impl Signal {
pub fn name(&self) -> Option<&'static str> {
match self {
Signal::Term => Some("term"),
Signal::Kill => Some("kill"),
Signal::Int => Some("int"),
Signal::Hup => Some("hup"),
Signal::Quit => Some("quit"),
Signal::Usr1 => Some("usr1"),
Signal::Usr2 => Some("usr2"),
Signal::Other(_) => None,
}
}
pub fn from_name(name: &str) -> Option<Self> {
match name {
"term" => Some(Signal::Term),
"kill" => Some(Signal::Kill),
"int" => Some(Signal::Int),
"hup" => Some(Signal::Hup),
"quit" => Some(Signal::Quit),
"usr1" => Some(Signal::Usr1),
"usr2" => Some(Signal::Usr2),
_ => None,
}
}
}
#[cfg(unix)]
impl Signal {
pub(crate) fn raw(self) -> i32 {
match self {
Signal::Term => libc::SIGTERM,
Signal::Kill => libc::SIGKILL,
Signal::Int => libc::SIGINT,
Signal::Hup => libc::SIGHUP,
Signal::Quit => libc::SIGQUIT,
Signal::Usr1 => libc::SIGUSR1,
Signal::Usr2 => libc::SIGUSR2,
Signal::Other(n) => n,
}
}
}
#[cfg(test)]
mod tests {
use super::Signal;
#[cfg(unix)]
#[test]
fn raw_maps_curated_variants_and_passes_other_through() {
assert_eq!(Signal::Term.raw(), libc::SIGTERM);
assert_eq!(Signal::Kill.raw(), libc::SIGKILL);
assert_eq!(Signal::Int.raw(), libc::SIGINT);
assert_eq!(Signal::Hup.raw(), libc::SIGHUP);
assert_eq!(Signal::Quit.raw(), libc::SIGQUIT);
assert_eq!(Signal::Usr1.raw(), libc::SIGUSR1);
assert_eq!(Signal::Usr2.raw(), libc::SIGUSR2);
assert_eq!(Signal::Other(64).raw(), 64);
}
const CURATED: &[Signal] = &[
Signal::Term,
Signal::Kill,
Signal::Int,
Signal::Hup,
Signal::Quit,
Signal::Usr1,
Signal::Usr2,
];
#[test]
fn name_pins_each_curated_variant() {
assert_eq!(Signal::Term.name(), Some("term"));
assert_eq!(Signal::Kill.name(), Some("kill"));
assert_eq!(Signal::Int.name(), Some("int"));
assert_eq!(Signal::Hup.name(), Some("hup"));
assert_eq!(Signal::Quit.name(), Some("quit"));
assert_eq!(Signal::Usr1.name(), Some("usr1"));
assert_eq!(Signal::Usr2.name(), Some("usr2"));
}
#[test]
fn other_has_no_curated_name() {
assert_eq!(Signal::Other(9).name(), None);
assert_eq!(Signal::Other(0).name(), None);
}
#[test]
fn name_from_name_round_trips_every_curated_variant() {
for &s in CURATED {
let name = s.name().expect("curated variant has a name");
assert_eq!(Signal::from_name(name), Some(s));
}
}
#[test]
fn from_name_rejects_unknown_and_other_without_defaulting() {
assert_eq!(Signal::from_name("Term"), None);
assert_eq!(Signal::from_name("sigterm"), None);
assert_eq!(Signal::from_name("other"), None);
assert_eq!(Signal::from_name("9"), None);
assert_eq!(Signal::from_name(""), None);
}
#[test]
fn signal_is_copy_eq_and_hashable() {
let sig = Signal::Hup;
let copy = sig; assert_eq!(sig, copy);
assert_ne!(Signal::Other(1), Signal::Other(2));
let mut set = std::collections::HashSet::new();
set.insert(Signal::Term);
set.insert(Signal::Term);
assert_eq!(set.len(), 1);
}
}