use crate::sys::{mode_to_flags, SourceId};
use crate::{PollMode, Poller};
use std::io;
use std::process::Child;
use std::time::Duration;
use rustix::event::kqueue;
use super::__private::PollerSealed;
use __private::FilterSealed;
pub trait PollerKqueueExt<F: Filter>: PollerSealed {
fn add_filter(&self, filter: F, key: usize, mode: PollMode) -> io::Result<()>;
fn modify_filter(&self, filter: F, key: usize, mode: PollMode) -> io::Result<()>;
fn delete_filter(&self, filter: F) -> io::Result<()>;
}
impl<F: Filter> PollerKqueueExt<F> for Poller {
#[inline(always)]
fn add_filter(&self, filter: F, key: usize, mode: PollMode) -> io::Result<()> {
self.poller.add_source(filter.source_id())?;
self.modify_filter(filter, key, mode)
}
fn modify_filter(&self, filter: F, key: usize, mode: PollMode) -> io::Result<()> {
self.poller.has_source(filter.source_id())?;
let event = filter.filter(kqueue::EventFlags::ADD | mode_to_flags(mode), key);
self.poller.submit_changes([event])
}
fn delete_filter(&self, filter: F) -> io::Result<()> {
let event = filter.filter(kqueue::EventFlags::DELETE, 0);
self.poller.submit_changes([event])?;
self.poller.remove_source(filter.source_id())
}
}
pub trait Filter: FilterSealed {}
unsafe impl<T: FilterSealed + ?Sized> FilterSealed for &T {
#[inline(always)]
fn filter(&self, flags: kqueue::EventFlags, key: usize) -> kqueue::Event {
(**self).filter(flags, key)
}
#[inline(always)]
fn source_id(&self) -> SourceId {
(**self).source_id()
}
}
impl<T: Filter + ?Sized> Filter for &T {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Signal(pub std::os::raw::c_int);
unsafe impl FilterSealed for Signal {
#[inline(always)]
fn filter(&self, flags: kqueue::EventFlags, key: usize) -> kqueue::Event {
kqueue::Event::new(
kqueue::EventFilter::Signal {
signal: rustix::process::Signal::from_raw(self.0).expect("invalid signal number"),
times: 0,
},
flags | kqueue::EventFlags::RECEIPT,
key as _,
)
}
#[inline(always)]
fn source_id(&self) -> SourceId {
SourceId::Signal(self.0)
}
}
impl Filter for Signal {}
#[derive(Debug)]
pub struct Process<'a> {
child: &'a Child,
ops: ProcessOps,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ProcessOps {
Exit,
Fork,
Exec,
}
impl<'a> Process<'a> {
pub unsafe fn new(child: &'a Child, ops: ProcessOps) -> Self {
Self { child, ops }
}
}
unsafe impl FilterSealed for Process<'_> {
#[inline(always)]
fn filter(&self, flags: kqueue::EventFlags, key: usize) -> kqueue::Event {
let events = match self.ops {
ProcessOps::Exit => kqueue::ProcessEvents::EXIT,
ProcessOps::Fork => kqueue::ProcessEvents::FORK,
ProcessOps::Exec => kqueue::ProcessEvents::EXEC,
};
kqueue::Event::new(
kqueue::EventFilter::Proc {
pid: rustix::process::Pid::from_child(self.child),
flags: events,
},
flags | kqueue::EventFlags::RECEIPT,
key as _,
)
}
#[inline(always)]
fn source_id(&self) -> SourceId {
SourceId::Pid(rustix::process::Pid::from_child(self.child))
}
}
impl Filter for Process<'_> {}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Timer {
pub id: usize,
pub timeout: Duration,
}
unsafe impl FilterSealed for Timer {
fn filter(&self, flags: kqueue::EventFlags, key: usize) -> kqueue::Event {
kqueue::Event::new(
kqueue::EventFilter::Timer {
ident: self.id as _,
timer: Some(self.timeout),
},
flags | kqueue::EventFlags::RECEIPT,
key as _,
)
}
#[inline(always)]
fn source_id(&self) -> SourceId {
SourceId::Timer(self.id)
}
}
impl Filter for Timer {}
mod __private {
use crate::sys::SourceId;
use rustix::event::kqueue;
#[doc(hidden)]
pub unsafe trait FilterSealed {
fn filter(&self, flags: kqueue::EventFlags, key: usize) -> kqueue::Event;
fn source_id(&self) -> SourceId;
}
}