1
+ use std:: iter:: FusedIterator ;
1
2
use std:: mem;
3
+ use std:: ops:: Range ;
2
4
use std:: os:: unix:: io:: RawFd ;
3
5
use std:: ptr:: { null, null_mut} ;
4
6
use libc:: { self , c_int} ;
@@ -59,14 +61,33 @@ impl FdSet {
59
61
///
60
62
/// [`select`]: fn.select.html
61
63
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
+ }
68
66
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
+ }
70
91
}
71
92
}
72
93
@@ -76,6 +97,46 @@ impl Default for FdSet {
76
97
}
77
98
}
78
99
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
+
79
140
/// Monitors file descriptors for readiness
80
141
///
81
142
/// 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 {
100
161
///
101
162
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
102
163
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 ,
106
167
timeout : T ) -> Result < c_int >
107
168
where
108
169
N : Into < Option < c_int > > ,
@@ -129,7 +190,7 @@ where
129
190
let writefds = writefds. map ( |set| set as * mut _ as * mut libc:: fd_set ) . unwrap_or ( null_mut ( ) ) ;
130
191
let errorfds = errorfds. map ( |set| set as * mut _ as * mut libc:: fd_set ) . unwrap_or ( null_mut ( ) ) ;
131
192
let timeout = timeout. map ( |tv| tv as * mut _ as * mut libc:: timeval )
132
- . unwrap_or ( null_mut ( ) ) ;
193
+ . unwrap_or ( null_mut ( ) ) ;
133
194
134
195
let res = unsafe {
135
196
libc:: select ( nfds, readfds, writefds, errorfds, timeout)
@@ -168,10 +229,10 @@ where
168
229
///
169
230
/// [`FdSet::highest`]: struct.FdSet.html#method.highest
170
231
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 ,
175
236
sigmask : S ) -> Result < c_int >
176
237
where
177
238
N : Into < Option < c_int > > ,
@@ -279,6 +340,20 @@ mod tests {
279
340
assert_eq ! ( set. highest( ) , Some ( 7 ) ) ;
280
341
}
281
342
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
+
282
357
#[ test]
283
358
fn test_select ( ) {
284
359
let ( r1, w1) = pipe ( ) . unwrap ( ) ;
@@ -311,9 +386,9 @@ mod tests {
311
386
312
387
let mut timeout = TimeVal :: seconds ( 10 ) ;
313
388
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 ,
317
392
& mut timeout) . unwrap( ) ) ;
318
393
assert ! ( fd_set. contains( r1) ) ;
319
394
assert ! ( !fd_set. contains( r2) ) ;
@@ -331,9 +406,9 @@ mod tests {
331
406
332
407
let mut timeout = TimeVal :: seconds ( 10 ) ;
333
408
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 ,
337
412
& mut timeout) . unwrap( ) ) ;
338
413
assert ! ( fd_set. contains( r1) ) ;
339
414
assert ! ( !fd_set. contains( r2) ) ;
0 commit comments