use std::io;
use std::iter::FusedIterator;
use std::ops::BitOr;
use crate::event;
use crate::os::OsQueue;
use crate::sys;
#[derive(Debug)]
pub struct Signals {
inner: sys::Signals,
}
impl Signals {
pub fn new(os_queue: &mut OsQueue, signals: SignalSet, id: event::Id) -> io::Result<Signals> {
debug_assert!(signals.size() != 0, "can't create `Signals` with an empty signal set");
sys::Signals::new(os_queue.selector(), signals, id)
.map(|inner| Signals { inner })
}
pub fn receive(&mut self) -> io::Result<Option<Signal>> {
self.inner.receive()
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SignalSet(u8);
const INTERRUPT: u8 = 1;
const QUIT: u8 = 1 << 1;
const TERMINATE: u8 = 1 << 2;
impl SignalSet {
pub const fn empty() -> SignalSet {
SignalSet(0)
}
pub const fn all() -> SignalSet {
SignalSet(INTERRUPT | QUIT | TERMINATE)
}
pub const fn size(self) -> usize {
self.0.count_ones() as usize
}
pub fn contains<S>(self, other: S) -> bool
where S: Into<SignalSet>,
{
let other = other.into();
(self.0 & other.0) == other.0
}
}
impl From<Signal> for SignalSet {
fn from(signal: Signal) -> Self {
SignalSet(match signal {
Signal::Interrupt => INTERRUPT,
Signal::Quit => QUIT,
Signal::Terminate => TERMINATE,
})
}
}
impl BitOr for SignalSet {
type Output = SignalSet;
fn bitor(self, rhs: Self) -> Self {
SignalSet(self.0 | rhs.0)
}
}
impl BitOr<Signal> for SignalSet {
type Output = SignalSet;
fn bitor(self, rhs: Signal) -> Self {
self | Into::<SignalSet>::into(rhs)
}
}
impl IntoIterator for SignalSet {
type Item = Signal;
type IntoIter = SignalSetIter;
fn into_iter(self) -> Self::IntoIter {
SignalSetIter(self)
}
}
#[derive(Debug)]
pub struct SignalSetIter(SignalSet);
impl Iterator for SignalSetIter {
type Item = Signal;
fn next(&mut self) -> Option<Self::Item> {
let n = (self.0).0.trailing_zeros();
match n {
0 => Some(Signal::Interrupt),
1 => Some(Signal::Quit),
2 => Some(Signal::Terminate),
_ => None,
}.map(|signal| {
(self.0).0 &= !(1 << n);
signal
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.0.size();
(size, Some(size))
}
fn count(self) -> usize {
self.0.size()
}
}
impl ExactSizeIterator for SignalSetIter {
fn len(&self) -> usize {
self.0.size()
}
}
impl FusedIterator for SignalSetIter {}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Signal {
Interrupt,
Terminate,
Quit,
}
impl Signal {
pub(crate) fn into_raw(self) -> libc::c_int {
match self {
Signal::Interrupt => libc::SIGINT,
Signal::Quit => libc::SIGQUIT,
Signal::Terminate => libc::SIGTERM,
}
}
pub(crate) fn from_raw(raw_signal: libc::c_int) -> Option<Signal> {
match raw_signal {
libc::SIGINT => Some(Signal::Interrupt),
libc::SIGQUIT => Some(Signal::Quit),
libc::SIGTERM => Some(Signal::Terminate),
_ => None,
}
}
}
impl BitOr for Signal {
type Output = SignalSet;
fn bitor(self, rhs: Self) -> SignalSet {
Into::<SignalSet>::into(self) | rhs
}
}
impl BitOr<SignalSet> for Signal {
type Output = SignalSet;
fn bitor(self, rhs: SignalSet) -> SignalSet {
rhs | self
}
}
#[cfg(test)]
mod tests {
use crate::os::Signal;
#[test]
fn signal_from_raw() {
assert_eq!(Signal::from_raw(libc::SIGINT), Some(Signal::Interrupt));
assert_eq!(Signal::from_raw(libc::SIGQUIT), Some(Signal::Quit));
assert_eq!(Signal::from_raw(libc::SIGTERM), Some(Signal::Terminate));
assert_eq!(Signal::from_raw(libc::SIGSTOP), None);
}
#[test]
fn signal_into_raw() {
assert_eq!(Signal::Interrupt.into_raw(), libc::SIGINT);
assert_eq!(Signal::Quit.into_raw(), libc::SIGQUIT);
assert_eq!(Signal::Terminate.into_raw(), libc::SIGTERM);
}
#[test]
fn raw_signal() {
assert_eq!(Signal::from_raw(libc::SIGINT).unwrap().into_raw(), libc::SIGINT);
assert_eq!(Signal::from_raw(libc::SIGQUIT).unwrap().into_raw(), libc::SIGQUIT);
assert_eq!(Signal::from_raw(libc::SIGTERM).unwrap().into_raw(), libc::SIGTERM);
}
}