selecting/
lib.rs

1//!Cross-platform wrapper over select.
2//!
3//!This library provides simple interface over POSIX's `select` enabling you to write
4//!very simple async programs using `std` networking primitives.
5//!
6//!But if you want performance you should look for `tokio` or `mio`
7
8mod sys;
9
10use sys::FdSet;
11pub use sys::AsRawFd;
12
13use std::io;
14use core::time;
15
16pub use sys::FD_LIMIT;
17
18///Represents successful select call.
19///
20///It contains number of fd ready.
21///And also set of these ids, allowing to query which fd is ready.
22pub struct SelectResult {
23    count: usize,
24    read: FdSet,
25    write: FdSet,
26    except: FdSet,
27}
28
29impl SelectResult {
30    #[inline]
31    ///Returns total number of file descriptors ready.
32    pub const fn len(&self) -> usize {
33        self.count
34    }
35
36    #[inline]
37    ///Returns whether specified `source` is read ready.
38    pub fn is_read<T: AsRawFd>(&self, source: &T) -> bool {
39        self.read.is_present(source)
40    }
41
42    #[inline]
43    ///Returns whether specified `source` is write ready.
44    pub fn is_write<T: AsRawFd>(&self, source: &T) -> bool {
45        self.write.is_present(source)
46    }
47
48    #[inline]
49    ///Returns whether specified `source` is except ready.
50    pub fn is_except<T: AsRawFd>(&self, source: &T) -> bool {
51        self.except.is_present(source)
52    }
53
54}
55
56#[derive(Clone)]
57///Select abstraction allowing you to monitor specified sockets.
58///
59///Selector itself represents set of file descriptors to monitor, as such it is possible
60///to copy it.
61///Normally select modifies list of file descriptors, but `Selector` always copies existing list,
62///avoiding these modifications.
63///
64///## Performance recommendations
65///
66///Generally limited to 64 file descriptors, but you should only use select when you have ~10 fds
67///otherwise modern API like `kqueue` or `epoll` would yield much better performance.
68///
69///- Call select only when getting would block from syscall;
70///- Limit number of selects, allowing it to accumulate events;
71pub struct Selector {
72    read: FdSet,
73    write: FdSet,
74    except: FdSet,
75}
76
77impl Selector {
78    #[inline]
79    ///Creates new instance with no sockets to monitor.
80    pub fn new() -> Self {
81        Self {
82            read: FdSet::new(),
83            write: FdSet::new(),
84            except: FdSet::new(),
85        }
86    }
87
88    #[inline]
89    ///Adds `source` to monitor for read ops.
90    ///
91    ///Panics when goes over `FD_LIMIT`
92    pub fn add_read<T: AsRawFd>(&mut self, source: &T) {
93        assert!(self.read.len() < sys::FD_LIMIT);
94        self.read.add(source);
95    }
96
97    #[inline]
98    ///Adds `source` to monitor for write ops.
99    ///
100    ///Panics when goes over `FD_LIMIT`
101    pub fn add_write<T: AsRawFd>(&mut self, source: &T) {
102        assert!(self.write.len() < sys::FD_LIMIT);
103        self.write.add(source);
104    }
105
106    #[inline]
107    ///Adds `source` to monitor for exceptional ops.
108    ///
109    ///Panics when goes over `FD_LIMIT`
110    pub fn add_except<T: AsRawFd>(&mut self, source: &T) {
111        assert!(self.except.len() < sys::FD_LIMIT);
112        self.except.add(source);
113    }
114
115
116    #[inline]
117    ///Removes all fds from read monitoring
118    pub fn clear_read(&mut self) {
119        self.read.clear();
120    }
121
122    #[inline]
123    ///Removes all fds from write monitoring
124    pub fn clear_write(&mut self) {
125        self.write.clear();
126    }
127
128    #[inline]
129    ///Removes all fds from except monitoring
130    pub fn clear_except(&mut self) {
131        self.except.clear();
132    }
133
134
135    #[inline]
136    ///Performs select, awaiting indefinitely until at least one descriptor has changes.
137    pub fn select(&self) -> io::Result<SelectResult> {
138        let mut result = SelectResult {
139            count: 0,
140            read: self.read.clone(),
141            write: self.write.clone(),
142            except: self.except.clone(),
143        };
144
145        result.count = sys::select(&mut result.read, &mut result.write, &mut result.except)?;
146        Ok(result)
147    }
148
149    #[inline]
150    ///Performs select, checking file descriptors for changes and returning immediately.
151    pub fn try_select(&self) -> io::Result<SelectResult> {
152        let mut result = SelectResult {
153            count: 0,
154            read: self.read.clone(),
155            write: self.write.clone(),
156            except: self.except.clone(),
157        };
158
159        result.count = sys::select_timeout(&mut result.read, &mut result.write, &mut result.except, time::Duration::from_secs(0))?;
160        Ok(result)
161    }
162
163    #[inline]
164    ///Performs select, awaiting at most `time` until at least one descriptor has changes.
165    pub fn select_timeout(&self, time: time::Duration) -> io::Result<SelectResult> {
166        let mut result = SelectResult {
167            count: 0,
168            read: self.read.clone(),
169            write: self.write.clone(),
170            except: self.except.clone(),
171        };
172
173        result.count = sys::select_timeout(&mut result.read, &mut result.write, &mut result.except, time)?;
174        Ok(result)
175    }
176}