#![warn(
missing_debug_implementations,
missing_docs,
rust_2018_idioms,
unused_qualifications,
unused_results,
variant_size_differences
)]
#![cfg_attr(test, deny(warnings))]
#![doc(test(attr(deny(warnings))))]
#![allow(clippy::len_without_is_empty)]
use std::iter::FusedIterator;
use std::num::NonZeroU8;
use std::ops::BitOr;
use std::{fmt, io};
use mio::{event, Interest, Registry, Token};
mod sys;
#[derive(Debug)]
pub struct Signals {
sys: sys::Signals,
}
impl Signals {
pub fn new(signals: SignalSet) -> io::Result<Signals> {
sys::Signals::new(signals).map(|sys| Signals { sys })
}
pub fn receive(&mut self) -> io::Result<Option<Signal>> {
self.sys.receive()
}
}
impl event::Source for Signals {
fn register(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.sys.register(registry, token, interests)
}
fn reregister(
&mut self,
registry: &Registry,
token: Token,
interests: Interest,
) -> io::Result<()> {
self.sys.reregister(registry, token, interests)
}
fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
self.sys.deregister(registry)
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct SignalSet(NonZeroU8);
const INTERRUPT: u8 = 1;
const QUIT: u8 = 1 << 1;
const TERMINATE: u8 = 1 << 2;
const USER1: u8 = 1 << 3;
const USER2: u8 = 1 << 4;
impl SignalSet {
pub const fn all() -> SignalSet {
SignalSet(unsafe { NonZeroU8::new_unchecked(INTERRUPT | QUIT | TERMINATE | USER1 | USER2) })
}
pub const fn len(self) -> usize {
self.0.get().count_ones() as usize
}
pub fn contains<S>(self, other: S) -> bool
where
S: Into<SignalSet>,
{
let other = other.into();
(self.0.get() & other.0.get()) == other.0.get()
}
}
impl From<Signal> for SignalSet {
fn from(signal: Signal) -> Self {
SignalSet(unsafe {
NonZeroU8::new_unchecked(match signal {
Signal::Interrupt => INTERRUPT,
Signal::Quit => QUIT,
Signal::Terminate => TERMINATE,
Signal::User1 => USER1,
Signal::User2 => USER2,
})
})
}
}
impl BitOr for SignalSet {
type Output = SignalSet;
fn bitor(self, rhs: Self) -> Self {
SignalSet(unsafe { NonZeroU8::new_unchecked(self.0.get() | rhs.0.get()) })
}
}
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.0.get())
}
}
impl fmt::Debug for SignalSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.into_iter().fmt(f)
}
}
pub struct SignalSetIter(u8);
impl Iterator for SignalSetIter {
type Item = Signal;
fn next(&mut self) -> Option<Self::Item> {
let n = self.0.trailing_zeros();
match n {
0 => Some(Signal::Interrupt),
1 => Some(Signal::Quit),
2 => Some(Signal::Terminate),
3 => Some(Signal::User1),
4 => Some(Signal::User2),
_ => None,
}
.map(|signal| {
self.0 &= !(1 << n);
signal
})
}
fn size_hint(&self) -> (usize, Option<usize>) {
let size = self.len();
(size, Some(size))
}
fn count(self) -> usize {
self.len()
}
}
impl ExactSizeIterator for SignalSetIter {
fn len(&self) -> usize {
self.0.count_ones() as usize
}
}
impl FusedIterator for SignalSetIter {}
impl fmt::Debug for SignalSetIter {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut set = SignalSetIter(self.0);
if set.len() == 0 {
f.write_str("(empty)")
} else {
let first = set.next().unwrap();
first.fmt(f)?;
for signal in set {
f.write_str("|")?;
signal.fmt(f)?;
}
Ok(())
}
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub enum Signal {
Interrupt,
Terminate,
Quit,
User1,
User2,
}
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
}
}
pub fn send_signal(pid: u32, signal: Signal) -> io::Result<()> {
sys::send_signal(pid, signal)
}