1+ use std:: iter:: FusedIterator ;
12use std:: mem;
3+ use std:: ops:: Range ;
24use std:: os:: unix:: io:: RawFd ;
35use std:: ptr:: { null, null_mut} ;
46use 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
102163pub 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 >
107168where
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
170231pub 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 >
176237where
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