diff --git a/changelog/2202.changed.md b/changelog/2202.changed.md new file mode 100644 index 0000000000..c1306d7f7e --- /dev/null +++ b/changelog/2202.changed.md @@ -0,0 +1 @@ +`Epoll::wait` now takes `EpollTimeout` replacing `isize`. \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 62220a822f..b8beaa56ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -196,6 +196,9 @@ feature! { #[allow(missing_docs)] pub mod unistd; +#[cfg(any(feature = "poll", feature = "event"))] +mod poll_timeout; + use std::ffi::{CStr, CString, OsStr}; use std::mem::MaybeUninit; use std::os::unix::ffi::OsStrExt; diff --git a/src/poll.rs b/src/poll.rs index 4bc1a4b392..0144adbf0e 100644 --- a/src/poll.rs +++ b/src/poll.rs @@ -1,9 +1,10 @@ //! Wait for events to trigger on specific file descriptors use std::os::unix::io::{AsFd, AsRawFd, BorrowedFd}; -use std::time::Duration; use crate::errno::Errno; +pub use crate::poll_timeout::PollTimeout; use crate::Result; + /// This is a wrapper around `libc::pollfd`. /// /// It's meant to be used as an argument to the [`poll`](fn.poll.html) and @@ -175,229 +176,6 @@ libc_bitflags! { } } -/// Timeout argument for [`poll`]. -#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] -pub struct PollTimeout(i32); - -impl PollTimeout { - /// Blocks indefinitely. - /// - /// > Specifying a negative value in timeout means an infinite timeout. - pub const NONE: Self = Self(-1); - /// Returns immediately. - /// - /// > Specifying a timeout of zero causes poll() to return immediately, even if no file - /// > descriptors are ready. - pub const ZERO: Self = Self(0); - /// Blocks for at most [`std::i32::MAX`] milliseconds. - pub const MAX: Self = Self(i32::MAX); - /// Returns if `self` equals [`PollTimeout::NONE`]. - pub fn is_none(&self) -> bool { - // > Specifying a negative value in timeout means an infinite timeout. - *self <= Self::NONE - } - /// Returns if `self` does not equal [`PollTimeout::NONE`]. - pub fn is_some(&self) -> bool { - !self.is_none() - } - /// Returns the timeout in milliseconds if there is some, otherwise returns `None`. - pub fn as_millis(&self) -> Option { - self.is_some().then_some(u32::try_from(self.0).unwrap()) - } - /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`. - pub fn timeout(&self) -> Option { - self.as_millis() - .map(|x| Duration::from_millis(u64::from(x))) - } -} - -/// Error type for integer conversions into `PollTimeout`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum PollTimeoutTryFromError { - /// Passing a value less than -1 is invalid on some systems, see - /// . - TooNegative, - /// Passing a value greater than `i32::MAX` is invalid. - TooPositive, -} - -impl std::fmt::Display for PollTimeoutTryFromError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::TooNegative => write!(f, "Passed a negative timeout less than -1."), - Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.") - } - } -} - -impl std::error::Error for PollTimeoutTryFromError {} - -impl> From> for PollTimeout { - fn from(x: Option) -> Self { - x.map_or(Self::NONE, |x| x.into()) - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: Duration) -> std::result::Result { - Ok(Self( - i32::try_from(x.as_millis()) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )) - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: u128) -> std::result::Result { - Ok(Self( - i32::try_from(x) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )) - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: u64) -> std::result::Result { - Ok(Self( - i32::try_from(x) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )) - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: u32) -> std::result::Result { - Ok(Self( - i32::try_from(x) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )) - } -} -impl From for PollTimeout { - fn from(x: u16) -> Self { - Self(i32::from(x)) - } -} -impl From for PollTimeout { - fn from(x: u8) -> Self { - Self(i32::from(x)) - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: i128) -> std::result::Result { - match x { - ..=-2 => Err(PollTimeoutTryFromError::TooNegative), - -1.. => Ok(Self( - i32::try_from(x) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )), - } - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: i64) -> std::result::Result { - match x { - ..=-2 => Err(PollTimeoutTryFromError::TooNegative), - -1.. => Ok(Self( - i32::try_from(x) - .map_err(|_| PollTimeoutTryFromError::TooPositive)?, - )), - } - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: i32) -> std::result::Result { - match x { - ..=-2 => Err(PollTimeoutTryFromError::TooNegative), - -1.. => Ok(Self(x)), - } - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: i16) -> std::result::Result { - match x { - ..=-2 => Err(PollTimeoutTryFromError::TooNegative), - -1.. => Ok(Self(i32::from(x))), - } - } -} -impl TryFrom for PollTimeout { - type Error = PollTimeoutTryFromError; - fn try_from(x: i8) -> std::result::Result { - match x { - ..=-2 => Err(PollTimeoutTryFromError::TooNegative), - -1.. => Ok(Self(i32::from(x))), - } - } -} -impl TryFrom for Duration { - type Error = (); - fn try_from(x: PollTimeout) -> std::result::Result { - x.timeout().ok_or(()) - } -} -impl TryFrom for u128 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl TryFrom for u64 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl TryFrom for u32 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl TryFrom for u16 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl TryFrom for u8 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl From for i128 { - fn from(x: PollTimeout) -> Self { - Self::from(x.0) - } -} -impl From for i64 { - fn from(x: PollTimeout) -> Self { - Self::from(x.0) - } -} -impl From for i32 { - fn from(x: PollTimeout) -> Self { - x.0 - } -} -impl TryFrom for i16 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} -impl TryFrom for i8 { - type Error = >::Error; - fn try_from(x: PollTimeout) -> std::result::Result { - Self::try_from(x.0) - } -} - /// `poll` waits for one of a set of file descriptors to become ready to perform I/O. /// ([`poll(2)`](https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html)) /// diff --git a/src/poll_timeout.rs b/src/poll_timeout.rs new file mode 100644 index 0000000000..3f2dc4c4a1 --- /dev/null +++ b/src/poll_timeout.rs @@ -0,0 +1,224 @@ +use std::time::Duration; + +/// PollTimeout argument for polling. +#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] +pub struct PollTimeout(i32); + +impl PollTimeout { + /// Blocks indefinitely. + /// + /// > Specifying a negative value in timeout means an infinite timeout. + pub const NONE: Self = Self(-1); + /// Returns immediately. + /// + /// > Specifying a timeout of zero causes poll() to return immediately, even if no file + /// > descriptors are ready. + pub const ZERO: Self = Self(0); + /// Blocks for at most [`std::i32::MAX`] milliseconds. + pub const MAX: Self = Self(i32::MAX); + /// Returns if `self` equals [`PollTimeout::NONE`]. + pub fn is_none(&self) -> bool { + // > Specifying a negative value in timeout means an infinite timeout. + *self <= Self::NONE + } + /// Returns if `self` does not equal [`PollTimeout::NONE`]. + pub fn is_some(&self) -> bool { + !self.is_none() + } + /// Returns the timeout in milliseconds if there is some, otherwise returns `None`. + pub fn as_millis(&self) -> Option { + self.is_some().then_some(u32::try_from(self.0).unwrap()) + } + /// Returns the timeout as a `Duration` if there is some, otherwise returns `None`. + pub fn duration(&self) -> Option { + self.as_millis() + .map(|x| Duration::from_millis(u64::from(x))) + } +} + +/// Error type for integer conversions into `PollTimeout`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PollTimeoutTryFromError { + /// Passing a value less than -1 is invalid on some systems, see + /// . + TooNegative, + /// Passing a value greater than `i32::MAX` is invalid. + TooPositive, +} + +impl std::fmt::Display for PollTimeoutTryFromError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TooNegative => write!(f, "Passed a negative timeout less than -1."), + Self::TooPositive => write!(f, "Passed a positive timeout greater than `i32::MAX` milliseconds.") + } + } +} + +impl std::error::Error for PollTimeoutTryFromError {} + +impl> From> for PollTimeout { + fn from(x: Option) -> Self { + x.map_or(Self::NONE, |x| x.into()) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: Duration) -> std::result::Result { + Ok(Self( + i32::try_from(x.as_millis()) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u128) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u64) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: u32) -> std::result::Result { + Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )) + } +} +impl From for PollTimeout { + fn from(x: u16) -> Self { + Self(i32::from(x)) + } +} +impl From for PollTimeout { + fn from(x: u8) -> Self { + Self(i32::from(x)) + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i128) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i64) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self( + i32::try_from(x) + .map_err(|_| PollTimeoutTryFromError::TooPositive)?, + )), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i32) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(x)), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i16) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom for PollTimeout { + type Error = PollTimeoutTryFromError; + fn try_from(x: i8) -> std::result::Result { + match x { + ..=-2 => Err(PollTimeoutTryFromError::TooNegative), + -1.. => Ok(Self(i32::from(x))), + } + } +} +impl TryFrom for Duration { + type Error = (); + fn try_from(x: PollTimeout) -> std::result::Result { + x.duration().ok_or(()) + } +} +impl TryFrom for u128 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u64 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u32 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u16 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for u8 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl From for i128 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From for i64 { + fn from(x: PollTimeout) -> Self { + Self::from(x.0) + } +} +impl From for i32 { + fn from(x: PollTimeout) -> Self { + x.0 + } +} +impl TryFrom for i16 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} +impl TryFrom for i8 { + type Error = >::Error; + fn try_from(x: PollTimeout) -> std::result::Result { + Self::try_from(x.0) + } +} diff --git a/src/sys/epoll.rs b/src/sys/epoll.rs index 679f9c47d1..32b068e88b 100644 --- a/src/sys/epoll.rs +++ b/src/sys/epoll.rs @@ -1,5 +1,6 @@ use crate::errno::Errno; use crate::Result; +pub use crate::poll_timeout::PollTimeout as EpollTimeout; use libc::{self, c_int}; use std::mem; use std::os::unix::io::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd}; @@ -71,13 +72,13 @@ impl EpollEvent { /// A safe wrapper around [`epoll`](https://man7.org/linux/man-pages/man7/epoll.7.html). /// ``` -/// # use nix::sys::{epoll::{Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; +/// # use nix::sys::{epoll::{EpollTimeout, Epoll, EpollEvent, EpollFlags, EpollCreateFlags}, eventfd::{eventfd, EfdFlags}}; /// # use nix::unistd::write; /// # use std::os::unix::io::{OwnedFd, FromRawFd, AsFd}; /// # use std::time::{Instant, Duration}; /// # fn main() -> nix::Result<()> { /// const DATA: u64 = 17; -/// const MILLIS: u64 = 100; +/// const MILLIS: u8 = 100; /// /// // Create epoll /// let epoll = Epoll::new(EpollCreateFlags::empty())?; @@ -92,11 +93,11 @@ impl EpollEvent { /// /// // Wait on event /// let mut events = [EpollEvent::empty()]; -/// epoll.wait(&mut events, MILLIS as isize)?; +/// epoll.wait(&mut events, MILLIS)?; /// /// // Assert data correct & timeout didn't occur /// assert_eq!(events[0].data(), DATA); -/// assert!(now.elapsed() < Duration::from_millis(MILLIS)); +/// assert!(now.elapsed().as_millis() < MILLIS.into()); /// # Ok(()) /// # } /// ``` @@ -140,17 +141,17 @@ impl Epoll { /// (This can be thought of as fetching items from the ready list of the epoll instance.) /// /// [`epoll_wait`](https://man7.org/linux/man-pages/man2/epoll_wait.2.html) - pub fn wait( + pub fn wait>( &self, events: &mut [EpollEvent], - timeout: isize, + timeout: T, ) -> Result { let res = unsafe { libc::epoll_wait( self.0.as_raw_fd(), events.as_mut_ptr().cast(), events.len() as c_int, - timeout as c_int, + timeout.into().into(), ) };