diff options
Diffstat (limited to 'src/sys/select.rs')
-rw-r--r-- | src/sys/select.rs | 108 |
1 files changed, 84 insertions, 24 deletions
diff --git a/src/sys/select.rs b/src/sys/select.rs index 32569acc..bfc0e80e 100644 --- a/src/sys/select.rs +++ b/src/sys/select.rs @@ -1,4 +1,6 @@ +use std::iter::FusedIterator; use std::mem; +use std::ops::Range; use std::os::unix::io::RawFd; use std::ptr::{null, null_mut}; use libc::{self, c_int}; @@ -30,8 +32,9 @@ impl FdSet { unsafe { libc::FD_CLR(fd, &mut self.0) }; } - pub fn contains(&mut self, fd: RawFd) -> bool { - unsafe { libc::FD_ISSET(fd, &mut self.0) } + pub fn contains(&self, fd: RawFd) -> bool { + let mut copy = self.0; + unsafe { libc::FD_ISSET(fd, &mut copy) } } pub fn clear(&mut self) { @@ -58,15 +61,32 @@ impl FdSet { /// ``` /// /// [`select`]: fn.select.html - pub fn highest(&mut self) -> Option<RawFd> { - for i in (0..FD_SETSIZE).rev() { - let i = i as RawFd; - if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } { - return Some(i) - } - } + pub fn highest(&self) -> Option<RawFd> { + self.fds().next_back() + } - None + /// Returns an iterator over the file descriptors in the set. + /// + /// # Examples + /// + /// ``` + /// # extern crate nix; + /// # use nix::sys::select::FdSet; + /// # use std::os::unix::io::RawFd; + /// # fn main() { + /// let mut set = FdSet::new(); + /// set.insert(4); + /// set.insert(9); + /// let fds: Vec<RawFd> = set.fds().collect(); + /// assert_eq!(fds, vec![4, 9]); + /// # } + /// ``` + #[inline] + pub fn fds(&self) -> Fds { + Fds { + set: self, + range: 0..FD_SETSIZE, + } } } @@ -76,6 +96,46 @@ impl Default for FdSet { } } +/// Iterator over `FdSet`. +#[derive(Clone, Debug)] +pub struct Fds<'a> { + set: &'a FdSet, + range: Range<usize>, +} + +impl<'a> Iterator for Fds<'a> { + type Item = RawFd; + + fn next(&mut self) -> Option<RawFd> { + while let Some(i) = self.range.next() { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + let (_, upper) = self.range.size_hint(); + (0, upper) + } +} + +impl<'a> DoubleEndedIterator for Fds<'a> { + #[inline] + fn next_back(&mut self) -> Option<RawFd> { + while let Some(i) = self.range.next_back() { + if self.set.contains(i as RawFd) { + return Some(i as RawFd); + } + } + None + } +} + +impl<'a> FusedIterator for Fds<'a> {} + /// Monitors file descriptors for readiness /// /// Returns the total number of ready file descriptors in all sets. The sets are changed so that all @@ -100,9 +160,9 @@ impl Default for FdSet { /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest pub fn select<'a, N, R, W, E, T>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, + readfds: R, + writefds: W, + errorfds: E, timeout: T) -> Result<c_int> where N: Into<Option<c_int>>, @@ -129,7 +189,7 @@ where let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut()); let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval) - .unwrap_or(null_mut()); + .unwrap_or(null_mut()); let res = unsafe { libc::select(nfds, readfds, writefds, errorfds, timeout) @@ -168,10 +228,10 @@ where /// /// [`FdSet::highest`]: struct.FdSet.html#method.highest pub fn pselect<'a, N, R, W, E, T, S>(nfds: N, - readfds: R, - writefds: W, - errorfds: E, - timeout: T, + readfds: R, + writefds: W, + errorfds: E, + timeout: T, sigmask: S) -> Result<c_int> where N: Into<Option<c_int>>, @@ -311,9 +371,9 @@ mod tests { let mut timeout = TimeVal::seconds(10); assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1), - &mut fd_set, - None, - None, + &mut fd_set, + None, + None, &mut timeout).unwrap()); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); @@ -331,9 +391,9 @@ mod tests { let mut timeout = TimeVal::seconds(10); assert_eq!(1, select(::std::cmp::max(r1, r2) + 1, - &mut fd_set, - None, - None, + &mut fd_set, + None, + None, &mut timeout).unwrap()); assert!(fd_set.contains(r1)); assert!(!fd_set.contains(r2)); |