Skip to content

Commit f94e882

Browse files
bors[bot]zombiezen
andauthored
Merge #1207
1207: Add select::FdSet::fds() method r=asomers a=zombiezen To be more consistent with most Rust APIs and enable cloning of the iterator, I made `FdSet::contains` operate on an immutable borrow instead of a mutable one by copying the set. If this is not desirable, I can roll that back from this PR and focus purely on the `fds()` method. Co-authored-by: Ross Light <[email protected]>
2 parents fdf828b + e8c7961 commit f94e882

File tree

2 files changed

+98
-21
lines changed

2 files changed

+98
-21
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
1717
identity for filesystem checks per-thread.
1818
(#[1163](https://github.com/nix-rust/nix/pull/1163))
1919
- Derived `Ord`, `PartialOrd` for `unistd::Pid` (#[1189](https://github.com/nix-rust/nix/pull/1189))
20+
- Added `select::FdSet::fds` method to iterate over file descriptors in a set.
21+
([#1207](https://github.com/nix-rust/nix/pull/1207))
2022

2123
### Changed
2224
- Changed `fallocate` return type from `c_int` to `()` (#[1201](https://github.com/nix-rust/nix/pull/1201))

src/sys/select.rs

+96-21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
use std::iter::FusedIterator;
12
use std::mem;
3+
use std::ops::Range;
24
use std::os::unix::io::RawFd;
35
use std::ptr::{null, null_mut};
46
use libc::{self, c_int};
@@ -59,14 +61,33 @@ impl FdSet {
5961
///
6062
/// [`select`]: fn.select.html
6163
pub fn highest(&mut self) -> Option<RawFd> {
62-
for i in (0..FD_SETSIZE).rev() {
63-
let i = i as RawFd;
64-
if unsafe { libc::FD_ISSET(i, self as *mut _ as *mut libc::fd_set) } {
65-
return Some(i)
66-
}
67-
}
64+
self.fds(None).next_back()
65+
}
6866

69-
None
67+
/// Returns an iterator over the file descriptors in the set.
68+
///
69+
/// For performance, it takes an optional higher bound: the iterator will
70+
/// not return any elements of the set greater than the given file
71+
/// descriptor.
72+
///
73+
/// # Examples
74+
///
75+
/// ```
76+
/// # extern crate nix;
77+
/// # use nix::sys::select::FdSet;
78+
/// # use std::os::unix::io::RawFd;
79+
/// let mut set = FdSet::new();
80+
/// set.insert(4);
81+
/// set.insert(9);
82+
/// let fds: Vec<RawFd> = set.fds(None).collect();
83+
/// assert_eq!(fds, vec![4, 9]);
84+
/// ```
85+
#[inline]
86+
pub fn fds(&mut self, highest: Option<RawFd>) -> Fds {
87+
Fds {
88+
set: self,
89+
range: 0..highest.map(|h| h as usize + 1).unwrap_or(FD_SETSIZE),
90+
}
7091
}
7192
}
7293

@@ -76,6 +97,46 @@ impl Default for FdSet {
7697
}
7798
}
7899

100+
/// Iterator over `FdSet`.
101+
#[derive(Debug)]
102+
pub struct Fds<'a> {
103+
set: &'a mut FdSet,
104+
range: Range<usize>,
105+
}
106+
107+
impl<'a> Iterator for Fds<'a> {
108+
type Item = RawFd;
109+
110+
fn next(&mut self) -> Option<RawFd> {
111+
while let Some(i) = self.range.next() {
112+
if self.set.contains(i as RawFd) {
113+
return Some(i as RawFd);
114+
}
115+
}
116+
None
117+
}
118+
119+
#[inline]
120+
fn size_hint(&self) -> (usize, Option<usize>) {
121+
let (_, upper) = self.range.size_hint();
122+
(0, upper)
123+
}
124+
}
125+
126+
impl<'a> DoubleEndedIterator for Fds<'a> {
127+
#[inline]
128+
fn next_back(&mut self) -> Option<RawFd> {
129+
while let Some(i) = self.range.next_back() {
130+
if self.set.contains(i as RawFd) {
131+
return Some(i as RawFd);
132+
}
133+
}
134+
None
135+
}
136+
}
137+
138+
impl<'a> FusedIterator for Fds<'a> {}
139+
79140
/// Monitors file descriptors for readiness
80141
///
81142
/// Returns the total number of ready file descriptors in all sets. The sets are changed so that all
@@ -100,9 +161,9 @@ impl Default for FdSet {
100161
///
101162
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
102163
pub fn select<'a, N, R, W, E, T>(nfds: N,
103-
readfds: R,
104-
writefds: W,
105-
errorfds: E,
164+
readfds: R,
165+
writefds: W,
166+
errorfds: E,
106167
timeout: T) -> Result<c_int>
107168
where
108169
N: Into<Option<c_int>>,
@@ -129,7 +190,7 @@ where
129190
let writefds = writefds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
130191
let errorfds = errorfds.map(|set| set as *mut _ as *mut libc::fd_set).unwrap_or(null_mut());
131192
let timeout = timeout.map(|tv| tv as *mut _ as *mut libc::timeval)
132-
.unwrap_or(null_mut());
193+
.unwrap_or(null_mut());
133194

134195
let res = unsafe {
135196
libc::select(nfds, readfds, writefds, errorfds, timeout)
@@ -168,10 +229,10 @@ where
168229
///
169230
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
170231
pub fn pselect<'a, N, R, W, E, T, S>(nfds: N,
171-
readfds: R,
172-
writefds: W,
173-
errorfds: E,
174-
timeout: T,
232+
readfds: R,
233+
writefds: W,
234+
errorfds: E,
235+
timeout: T,
175236
sigmask: S) -> Result<c_int>
176237
where
177238
N: Into<Option<c_int>>,
@@ -279,6 +340,20 @@ mod tests {
279340
assert_eq!(set.highest(), Some(7));
280341
}
281342

343+
#[test]
344+
fn fdset_fds() {
345+
let mut set = FdSet::new();
346+
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![]);
347+
set.insert(0);
348+
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0]);
349+
set.insert(90);
350+
assert_eq!(set.fds(None).collect::<Vec<_>>(), vec![0, 90]);
351+
352+
// highest limit
353+
assert_eq!(set.fds(Some(89)).collect::<Vec<_>>(), vec![0]);
354+
assert_eq!(set.fds(Some(90)).collect::<Vec<_>>(), vec![0, 90]);
355+
}
356+
282357
#[test]
283358
fn test_select() {
284359
let (r1, w1) = pipe().unwrap();
@@ -311,9 +386,9 @@ mod tests {
311386

312387
let mut timeout = TimeVal::seconds(10);
313388
assert_eq!(1, select(Some(fd_set.highest().unwrap() + 1),
314-
&mut fd_set,
315-
None,
316-
None,
389+
&mut fd_set,
390+
None,
391+
None,
317392
&mut timeout).unwrap());
318393
assert!(fd_set.contains(r1));
319394
assert!(!fd_set.contains(r2));
@@ -331,9 +406,9 @@ mod tests {
331406

332407
let mut timeout = TimeVal::seconds(10);
333408
assert_eq!(1, select(::std::cmp::max(r1, r2) + 1,
334-
&mut fd_set,
335-
None,
336-
None,
409+
&mut fd_set,
410+
None,
411+
None,
337412
&mut timeout).unwrap());
338413
assert!(fd_set.contains(r1));
339414
assert!(!fd_set.contains(r2));

0 commit comments

Comments
 (0)