#![doc(test(attr(deny(warnings))))]
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg))]
use std::borrow::Borrow;
use std::io::Error;
use std::os::unix::net::UnixStream;
use std::pin::Pin;
use std::task::{Context, Poll};
use libc::c_int;
pub use signal_hook::iterator::backend::Handle;
use signal_hook::iterator::backend::{OwningSignalIterator, PollResult, SignalDelivery};
use signal_hook::iterator::exfiltrator::{Exfiltrator, SignalOnly};
use async_io::Async;
use futures_lite::io::AsyncRead;
use futures_lite::stream::Stream;
pub struct SignalsInfo<E: Exfiltrator = SignalOnly>(OwningSignalIterator<Async<UnixStream>, E>);
impl<E: Exfiltrator> SignalsInfo<E> {
pub fn new<I, S>(signals: I) -> Result<Self, Error>
where
I: IntoIterator<Item = S>,
S: Borrow<c_int>,
E: Default,
{
Self::with_exfiltrator(signals, E::default())
}
pub fn with_exfiltrator<I, S>(signals: I, exfiltrator: E) -> Result<Self, Error>
where
I: IntoIterator<Item = S>,
S: Borrow<c_int>,
{
let (read, write) = Async::<UnixStream>::pair()?;
let inner = SignalDelivery::with_pipe(read, write.into_inner()?, exfiltrator, signals)?;
Ok(Self(OwningSignalIterator::new(inner)))
}
pub fn handle(&self) -> Handle {
self.0.handle()
}
}
impl<E: Exfiltrator> SignalsInfo<E> {
fn has_signals(read: &mut Async<UnixStream>, ctx: &mut Context<'_>) -> Result<bool, Error> {
match Pin::new(read).poll_read(ctx, &mut [0u8]) {
Poll::Pending => Ok(false),
Poll::Ready(Ok(num_read)) => Ok(num_read > 0),
Poll::Ready(Err(error)) => Err(error),
}
}
}
impl<E: Exfiltrator> Stream for SignalsInfo<E> {
type Item = E::Output;
fn poll_next(mut self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
match self.0.poll_signal(&mut |read| Self::has_signals(read, ctx)) {
PollResult::Signal(sig) => Poll::Ready(Some(sig)),
PollResult::Closed => Poll::Ready(None),
PollResult::Pending => Poll::Pending,
PollResult::Err(error) => panic!("Unexpected error: {}", error),
}
}
}
pub type Signals = SignalsInfo<SignalOnly>;