1 use event_imp::{Ready, ready_as_usize, ready_from_usize};
2
3 use std::ops;
4 use std::fmt;
5
6 /// Unix specific extensions to `Ready`
7 ///
8 /// Provides additional readiness event kinds that are available on unix
9 /// platforms. Unix platforms are able to provide readiness events for
10 /// additional socket events, such as HUP and error.
11 ///
12 /// HUP events occur when the remote end of a socket hangs up. In the TCP case,
13 /// this occurs when the remote end of a TCP socket shuts down writes.
14 ///
15 /// Error events occur when the socket enters an error state. In this case, the
16 /// socket will also receive a readable or writable event. Reading or writing to
17 /// the socket will result in an error.
18 ///
19 /// Conversion traits are implemented between `Ready` and `UnixReady`. See the
20 /// examples.
21 ///
22 /// For high level documentation on polling and readiness, see [`Poll`].
23 ///
24 /// # Examples
25 ///
26 /// Most of the time, all that is needed is using bit operations
27 ///
28 /// ```
29 /// use mio::Ready;
30 /// use mio::unix::UnixReady;
31 ///
32 /// let ready = Ready::readable() | UnixReady::hup();
33 ///
34 /// assert!(ready.is_readable());
35 /// assert!(UnixReady::from(ready).is_hup());
36 /// ```
37 ///
38 /// Basic conversion between ready types.
39 ///
40 /// ```
41 /// use mio::Ready;
42 /// use mio::unix::UnixReady;
43 ///
44 /// // Start with a portable ready
45 /// let ready = Ready::readable();
46 ///
47 /// // Convert to a unix ready, adding HUP
48 /// let mut unix_ready = UnixReady::from(ready) | UnixReady::hup();
49 ///
50 /// unix_ready.insert(UnixReady::error());
51 ///
52 /// // `unix_ready` maintains readable interest
53 /// assert!(unix_ready.is_readable());
54 /// assert!(unix_ready.is_hup());
55 /// assert!(unix_ready.is_error());
56 ///
57 /// // Convert back to `Ready`
58 /// let ready = Ready::from(unix_ready);
59 ///
60 /// // Readable is maintained
61 /// assert!(ready.is_readable());
62 /// ```
63 ///
64 /// Registering readable and error interest on a socket
65 ///
66 /// ```
67 /// # use std::error::Error;
68 /// # fn try_main() -> Result<(), Box<Error>> {
69 /// use mio::{Ready, Poll, PollOpt, Token};
70 /// use mio::net::TcpStream;
71 /// use mio::unix::UnixReady;
72 ///
73 /// let addr = "216.58.193.68:80".parse()?;
74 /// let socket = TcpStream::connect(&addr)?;
75 ///
76 /// let poll = Poll::new()?;
77 ///
78 /// poll.register(&socket,
79 /// Token(0),
80 /// Ready::readable() | UnixReady::error(),
81 /// PollOpt::edge())?;
82 /// # Ok(())
83 /// # }
84 /// #
85 /// # fn main() {
86 /// # try_main().unwrap();
87 /// # }
88 /// ```
89 ///
90 /// [`Poll`]: ../struct.Poll.html
91 /// [readiness]: struct.Poll.html#readiness-operations
92 #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
93 pub struct UnixReady(Ready);
94
95 const ERROR: usize = 0b00_0100;
96 const HUP: usize = 0b00_1000;
97
98 #[cfg(any(target_os = "dragonfly",
99 target_os = "freebsd", target_os = "ios", target_os = "macos"))]
100 const AIO: usize = 0b01_0000;
101
102 #[cfg(not(any(target_os = "dragonfly",
103 target_os = "freebsd", target_os = "ios", target_os = "macos")))]
104 const AIO: usize = 0b00_0000;
105
106 #[cfg(any(target_os = "freebsd"))]
107 const LIO: usize = 0b10_0000;
108
109 #[cfg(not(any(target_os = "freebsd")))]
110 const LIO: usize = 0b00_0000;
111
112 #[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
113 const PRI: usize = 0b100_0000;
114
115 #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "solaris")))]
116 const PRI: usize = 0;
117
118 // Export to support `Ready::all`
119 pub const READY_ALL: usize = ERROR | HUP | AIO | LIO | PRI;
120
121 #[test]
test_ready_all()122 fn test_ready_all() {
123 let readable = Ready::readable().as_usize();
124 let writable = Ready::writable().as_usize();
125
126 assert_eq!(
127 READY_ALL | readable | writable,
128 ERROR + HUP + AIO + LIO + PRI + readable + writable
129 );
130
131 // Issue #896.
132 #[cfg(any(target_os = "linux", target_os = "android", target_os = "solaris"))]
133 assert!(!Ready::from(UnixReady::priority()).is_writable());
134 }
135
136 impl UnixReady {
137 /// Returns a `Ready` representing AIO completion readiness
138 ///
139 /// See [`Poll`] for more documentation on polling.
140 ///
141 /// # Examples
142 ///
143 /// ```
144 /// use mio::unix::UnixReady;
145 ///
146 /// let ready = UnixReady::aio();
147 ///
148 /// assert!(ready.is_aio());
149 /// ```
150 ///
151 /// [`Poll`]: ../struct.Poll.html
152 #[inline]
153 #[cfg(any(target_os = "dragonfly",
154 target_os = "freebsd", target_os = "ios", target_os = "macos"))]
aio() -> UnixReady155 pub fn aio() -> UnixReady {
156 UnixReady(ready_from_usize(AIO))
157 }
158
159 #[cfg(not(any(target_os = "dragonfly",
160 target_os = "freebsd", target_os = "ios", target_os = "macos")))]
161 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
162 #[doc(hidden)]
aio() -> UnixReady163 pub fn aio() -> UnixReady {
164 UnixReady(Ready::empty())
165 }
166
167 /// Returns a `Ready` representing error readiness.
168 ///
169 /// **Note that only readable and writable readiness is guaranteed to be
170 /// supported on all platforms**. This means that `error` readiness
171 /// should be treated as a hint. For more details, see [readiness] in the
172 /// poll documentation.
173 ///
174 /// See [`Poll`] for more documentation on polling.
175 ///
176 /// # Examples
177 ///
178 /// ```
179 /// use mio::unix::UnixReady;
180 ///
181 /// let ready = UnixReady::error();
182 ///
183 /// assert!(ready.is_error());
184 /// ```
185 ///
186 /// [`Poll`]: ../struct.Poll.html
187 /// [readiness]: ../struct.Poll.html#readiness-operations
188 #[inline]
error() -> UnixReady189 pub fn error() -> UnixReady {
190 UnixReady(ready_from_usize(ERROR))
191 }
192
193 /// Returns a `Ready` representing HUP readiness.
194 ///
195 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
196 /// connection, or shut down the writing half of the connection.
197 ///
198 /// **Note that only readable and writable readiness is guaranteed to be
199 /// supported on all platforms**. This means that `hup` readiness
200 /// should be treated as a hint. For more details, see [readiness] in the
201 /// poll documentation. It is also unclear if HUP readiness will remain in 0.7. See
202 /// [here][issue-941].
203 ///
204 /// See [`Poll`] for more documentation on polling.
205 ///
206 /// # Examples
207 ///
208 /// ```
209 /// use mio::unix::UnixReady;
210 ///
211 /// let ready = UnixReady::hup();
212 ///
213 /// assert!(ready.is_hup());
214 /// ```
215 ///
216 /// [`Poll`]: ../struct.Poll.html
217 /// [readiness]: ../struct.Poll.html#readiness-operations
218 /// [issue-941]: https://github.com/tokio-rs/mio/issues/941
219 #[inline]
hup() -> UnixReady220 pub fn hup() -> UnixReady {
221 UnixReady(ready_from_usize(HUP))
222 }
223
224 /// Returns a `Ready` representing LIO completion readiness
225 ///
226 /// See [`Poll`] for more documentation on polling.
227 ///
228 /// # Examples
229 ///
230 /// ```
231 /// use mio::unix::UnixReady;
232 ///
233 /// let ready = UnixReady::lio();
234 ///
235 /// assert!(ready.is_lio());
236 /// ```
237 ///
238 /// [`Poll`]: struct.Poll.html
239 #[inline]
240 #[cfg(any(target_os = "freebsd"))]
lio() -> UnixReady241 pub fn lio() -> UnixReady {
242 UnixReady(ready_from_usize(LIO))
243 }
244
245 /// Returns a `Ready` representing priority (`EPOLLPRI`) readiness
246 ///
247 /// See [`Poll`] for more documentation on polling.
248 ///
249 /// # Examples
250 ///
251 /// ```
252 /// use mio::unix::UnixReady;
253 ///
254 /// let ready = UnixReady::priority();
255 ///
256 /// assert!(ready.is_priority());
257 /// ```
258 ///
259 /// [`Poll`]: struct.Poll.html
260 #[inline]
261 #[cfg(any(target_os = "linux",
262 target_os = "android", target_os = "solaris"))]
priority() -> UnixReady263 pub fn priority() -> UnixReady {
264 UnixReady(ready_from_usize(PRI))
265 }
266
267 /// Returns true if `Ready` contains AIO readiness
268 ///
269 /// See [`Poll`] for more documentation on polling.
270 ///
271 /// # Examples
272 ///
273 /// ```
274 /// use mio::unix::UnixReady;
275 ///
276 /// let ready = UnixReady::aio();
277 ///
278 /// assert!(ready.is_aio());
279 /// ```
280 ///
281 /// [`Poll`]: ../struct.Poll.html
282 #[inline]
283 #[cfg(any(target_os = "dragonfly",
284 target_os = "freebsd", target_os = "ios", target_os = "macos"))]
is_aio(&self) -> bool285 pub fn is_aio(&self) -> bool {
286 self.contains(ready_from_usize(AIO))
287 }
288
289 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
290 #[cfg(feature = "with-deprecated")]
291 #[cfg(not(any(target_os = "dragonfly",
292 target_os = "freebsd", target_os = "ios", target_os = "macos")))]
293 #[doc(hidden)]
is_aio(&self) -> bool294 pub fn is_aio(&self) -> bool {
295 false
296 }
297
298 /// Returns true if the value includes error readiness
299 ///
300 /// **Note that only readable and writable readiness is guaranteed to be
301 /// supported on all platforms**. This means that `error` readiness should
302 /// be treated as a hint. For more details, see [readiness] in the poll
303 /// documentation.
304 ///
305 /// See [`Poll`] for more documentation on polling.
306 ///
307 /// # Examples
308 ///
309 /// ```
310 /// use mio::unix::UnixReady;
311 ///
312 /// let ready = UnixReady::error();
313 ///
314 /// assert!(ready.is_error());
315 /// ```
316 ///
317 /// [`Poll`]: ../struct.Poll.html
318 /// [readiness]: ../struct.Poll.html#readiness-operations
319 #[inline]
is_error(&self) -> bool320 pub fn is_error(&self) -> bool {
321 self.contains(ready_from_usize(ERROR))
322 }
323
324 /// Returns true if the value includes HUP readiness
325 ///
326 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
327 /// connection, or shut down the writing half of the connection.
328 ///
329 /// **Note that only readable and writable readiness is guaranteed to be
330 /// supported on all platforms**. This means that `hup` readiness
331 /// should be treated as a hint. For more details, see [readiness] in the
332 /// poll documentation.
333 ///
334 /// See [`Poll`] for more documentation on polling.
335 ///
336 /// # Examples
337 ///
338 /// ```
339 /// use mio::unix::UnixReady;
340 ///
341 /// let ready = UnixReady::hup();
342 ///
343 /// assert!(ready.is_hup());
344 /// ```
345 ///
346 /// [`Poll`]: ../struct.Poll.html
347 /// [readiness]: ../struct.Poll.html#readiness-operations
348 #[inline]
is_hup(&self) -> bool349 pub fn is_hup(&self) -> bool {
350 self.contains(ready_from_usize(HUP))
351 }
352
353 /// Returns true if `Ready` contains LIO readiness
354 ///
355 /// See [`Poll`] for more documentation on polling.
356 ///
357 /// # Examples
358 ///
359 /// ```
360 /// use mio::unix::UnixReady;
361 ///
362 /// let ready = UnixReady::lio();
363 ///
364 /// assert!(ready.is_lio());
365 /// ```
366 #[inline]
367 #[cfg(any(target_os = "freebsd"))]
is_lio(&self) -> bool368 pub fn is_lio(&self) -> bool {
369 self.contains(ready_from_usize(LIO))
370 }
371
372 /// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
373 ///
374 /// See [`Poll`] for more documentation on polling.
375 ///
376 /// # Examples
377 ///
378 /// ```
379 /// use mio::unix::UnixReady;
380 ///
381 /// let ready = UnixReady::priority();
382 ///
383 /// assert!(ready.is_priority());
384 /// ```
385 ///
386 /// [`Poll`]: struct.Poll.html
387 #[inline]
388 #[cfg(any(target_os = "linux",
389 target_os = "android", target_os = "solaris"))]
is_priority(&self) -> bool390 pub fn is_priority(&self) -> bool {
391 self.contains(ready_from_usize(PRI))
392 }
393 }
394
395 impl From<Ready> for UnixReady {
from(src: Ready) -> UnixReady396 fn from(src: Ready) -> UnixReady {
397 UnixReady(src)
398 }
399 }
400
401 impl From<UnixReady> for Ready {
from(src: UnixReady) -> Ready402 fn from(src: UnixReady) -> Ready {
403 src.0
404 }
405 }
406
407 impl ops::Deref for UnixReady {
408 type Target = Ready;
409
deref(&self) -> &Ready410 fn deref(&self) -> &Ready {
411 &self.0
412 }
413 }
414
415 impl ops::DerefMut for UnixReady {
deref_mut(&mut self) -> &mut Ready416 fn deref_mut(&mut self) -> &mut Ready {
417 &mut self.0
418 }
419 }
420
421 impl ops::BitOr for UnixReady {
422 type Output = UnixReady;
423
424 #[inline]
bitor(self, other: UnixReady) -> UnixReady425 fn bitor(self, other: UnixReady) -> UnixReady {
426 (self.0 | other.0).into()
427 }
428 }
429
430 impl ops::BitXor for UnixReady {
431 type Output = UnixReady;
432
433 #[inline]
bitxor(self, other: UnixReady) -> UnixReady434 fn bitxor(self, other: UnixReady) -> UnixReady {
435 (self.0 ^ other.0).into()
436 }
437 }
438
439 impl ops::BitAnd for UnixReady {
440 type Output = UnixReady;
441
442 #[inline]
bitand(self, other: UnixReady) -> UnixReady443 fn bitand(self, other: UnixReady) -> UnixReady {
444 (self.0 & other.0).into()
445 }
446 }
447
448 impl ops::Sub for UnixReady {
449 type Output = UnixReady;
450
451 #[inline]
sub(self, other: UnixReady) -> UnixReady452 fn sub(self, other: UnixReady) -> UnixReady {
453 ready_from_usize(ready_as_usize(self.0) & !ready_as_usize(other.0)).into()
454 }
455 }
456
457 #[deprecated(since = "0.6.10", note = "removed")]
458 #[cfg(feature = "with-deprecated")]
459 #[doc(hidden)]
460 impl ops::Not for UnixReady {
461 type Output = UnixReady;
462
463 #[inline]
not(self) -> UnixReady464 fn not(self) -> UnixReady {
465 (!self.0).into()
466 }
467 }
468
469 impl fmt::Debug for UnixReady {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result470 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
471 let mut one = false;
472 let flags = [
473 (UnixReady(Ready::readable()), "Readable"),
474 (UnixReady(Ready::writable()), "Writable"),
475 (UnixReady::error(), "Error"),
476 (UnixReady::hup(), "Hup"),
477 #[allow(deprecated)]
478 (UnixReady::aio(), "Aio"),
479 #[cfg(any(target_os = "linux",
480 target_os = "android", target_os = "solaris"))]
481 (UnixReady::priority(), "Priority"),
482 ];
483
484 for &(flag, msg) in &flags {
485 if self.contains(flag) {
486 if one { write!(fmt, " | ")? }
487 write!(fmt, "{}", msg)?;
488
489 one = true
490 }
491 }
492
493 if !one {
494 fmt.write_str("(empty)")?;
495 }
496
497 Ok(())
498 }
499 }
500