summaryrefslogtreecommitdiff
path: root/src/sys/select.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/select.rs')
-rw-r--r--src/sys/select.rs108
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));