use std::{io, os::unix::io::RawFd};
#[cfg(target_os = "linux")]
mod epoll;
#[cfg(target_os = "linux")]
use epoll::Epoll as Poller;
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
mod kqueue;
#[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
))]
use kqueue::Kqueue as Poller;
#[derive(Copy, Clone, Debug)]
pub enum Mode {
OneShot,
Level,
Edge,
}
#[derive(Copy, Clone, Debug)]
pub struct Interest {
pub readable: bool,
pub writable: bool,
}
impl Interest {
pub const EMPTY: Interest = Interest {
readable: false,
writable: false,
};
pub const READ: Interest = Interest {
readable: true,
writable: false,
};
pub const WRITE: Interest = Interest {
readable: false,
writable: true,
};
pub const BOTH: Interest = Interest {
readable: true,
writable: true,
};
}
#[derive(Copy, Clone, Debug)]
pub struct Readiness {
pub readable: bool,
pub writable: bool,
pub error: bool,
}
impl Readiness {
pub const EMPTY: Readiness = Readiness {
readable: false,
writable: false,
error: false,
};
}
#[derive(Debug)]
pub(crate) struct PollEvent {
pub(crate) readiness: Readiness,
pub(crate) token: Token,
}
#[derive(Debug)]
pub struct TokenFactory {
id: u32,
sub_id: u32,
}
impl TokenFactory {
pub(crate) fn new(id: u32) -> TokenFactory {
TokenFactory { id, sub_id: 0 }
}
pub fn token(&mut self) -> Token {
let token = Token {
id: self.id,
sub_id: self.sub_id,
};
self.sub_id += 1;
token
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Token {
pub(crate) id: u32,
pub(crate) sub_id: u32,
}
#[allow(dead_code)]
impl Token {
pub(crate) fn to_u64(self) -> u64 {
((self.id as u64) << 32) + self.sub_id as u64
}
pub(crate) fn from_u64(i: u64) -> Token {
Token {
id: (i >> 32) as u32,
sub_id: (i & std::u32::MAX as u64) as u32,
}
}
pub(crate) fn to_u32(self) -> u32 {
(self.id << 16) + self.sub_id
}
pub(crate) fn from_u32(i: u32) -> Token {
Token {
id: (i >> 16),
sub_id: (i & std::u16::MAX as u32),
}
}
pub fn invalid() -> Token {
Token {
id: std::u32::MAX,
sub_id: std::u32::MAX,
}
}
pub fn is_invalid(self) -> bool {
self.id == std::u32::MAX && self.sub_id == std::u32::MAX
}
pub fn with_sub_id(self, sub_id: u32) -> Token {
Self { sub_id, ..self }
}
#[cfg(target_pointer_width = "64")]
pub(crate) fn to_usize(self) -> usize {
self.to_u64() as usize
}
#[cfg(target_pointer_width = "32")]
pub(crate) fn to_usize(self) -> usize {
self.to_u32() as usize
}
#[cfg(target_pointer_width = "64")]
pub(crate) fn from_usize(i: usize) -> Token {
Self::from_u64(i as u64)
}
#[cfg(target_pointer_width = "32")]
pub(crate) fn from_usize(i: usize) -> Token {
Self::from_u64(i as u64)
}
}
pub struct Poll {
poller: Poller,
}
impl std::fmt::Debug for Poll {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("Poll { ... }")
}
}
impl Poll {
pub(crate) fn new() -> io::Result<Poll> {
Ok(Poll {
poller: Poller::new()?,
})
}
pub(crate) fn poll(
&mut self,
timeout: Option<std::time::Duration>,
) -> io::Result<Vec<PollEvent>> {
self.poller.poll(timeout)
}
pub fn register(
&mut self,
fd: RawFd,
interest: Interest,
mode: Mode,
token: Token,
) -> io::Result<()> {
if token.is_invalid() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Invalid Token provided to register().",
));
}
self.poller.register(fd, interest, mode, token)
}
pub fn reregister(
&mut self,
fd: RawFd,
interest: Interest,
mode: Mode,
token: Token,
) -> io::Result<()> {
if token.is_invalid() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Invalid Token provided to reregister().",
));
}
self.poller.reregister(fd, interest, mode, token)
}
pub fn unregister(&mut self, fd: RawFd) -> io::Result<()> {
self.poller.unregister(fd)
}
}
#[cfg(test)]
mod tests {
use super::Token;
#[test]
fn token_convert_u64() {
let t = Token {
id: 0x1337,
sub_id: 0x42,
};
assert_eq!(t.to_u64(), 0x0000133700000042);
let t2 = Token::from_u64(0x0000133700000042);
assert_eq!(t, t2);
}
#[test]
fn token_convert_u32() {
let t = Token {
id: 0x1337,
sub_id: 0x42,
};
assert_eq!(t.to_u32(), 0x13370042);
let t2 = Token::from_u32(0x13370042);
assert_eq!(t, t2);
}
#[test]
fn token_with_sub_id() {
let t1 = Token {
id: 0x1234,
sub_id: 0,
};
let t2 = t1.with_sub_id(0xABCD);
assert_eq!(
t1,
Token {
id: 0x1234,
sub_id: 0
}
);
assert_eq!(
t2,
Token {
id: 0x1234,
sub_id: 0xABCD
}
);
}
}