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(
113 target_os = "android",
114 target_os = "illumos",
115 target_os = "linux",
116 target_os = "solaris"
117 ))]
118 const PRI: usize = 0b100_0000;
119
120 #[cfg(not(any(
121 target_os = "android",
122 target_os = "illumos",
123 target_os = "linux",
124 target_os = "solaris"
125 )))]
126 const PRI: usize = 0;
127
128 // Export to support `Ready::all`
129 pub const READY_ALL: usize = ERROR | HUP | AIO | LIO | PRI;
130
131 #[test]
test_ready_all()132 fn test_ready_all() {
133 let readable = Ready::readable().as_usize();
134 let writable = Ready::writable().as_usize();
135
136 assert_eq!(
137 READY_ALL | readable | writable,
138 ERROR + HUP + AIO + LIO + PRI + readable + writable
139 );
140
141 // Issue #896.
142 #[cfg(any(
143 target_os = "android",
144 target_os = "illumos",
145 target_os = "linux",
146 target_os = "solaris"
147 ))]
148 assert!(!Ready::from(UnixReady::priority()).is_writable());
149 }
150
151 impl UnixReady {
152 /// Returns a `Ready` representing AIO completion readiness
153 ///
154 /// See [`Poll`] for more documentation on polling.
155 ///
156 /// # Examples
157 ///
158 /// ```
159 /// use mio::unix::UnixReady;
160 ///
161 /// let ready = UnixReady::aio();
162 ///
163 /// assert!(ready.is_aio());
164 /// ```
165 ///
166 /// [`Poll`]: ../struct.Poll.html
167 #[inline]
168 #[cfg(any(target_os = "dragonfly",
169 target_os = "freebsd", target_os = "ios", target_os = "macos"))]
aio() -> UnixReady170 pub fn aio() -> UnixReady {
171 UnixReady(ready_from_usize(AIO))
172 }
173
174 #[cfg(not(any(target_os = "dragonfly",
175 target_os = "freebsd", target_os = "ios", target_os = "macos")))]
176 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
177 #[doc(hidden)]
aio() -> UnixReady178 pub fn aio() -> UnixReady {
179 UnixReady(Ready::empty())
180 }
181
182 /// Returns a `Ready` representing error readiness.
183 ///
184 /// **Note that only readable and writable readiness is guaranteed to be
185 /// supported on all platforms**. This means that `error` readiness
186 /// should be treated as a hint. For more details, see [readiness] in the
187 /// poll documentation.
188 ///
189 /// See [`Poll`] for more documentation on polling.
190 ///
191 /// # Examples
192 ///
193 /// ```
194 /// use mio::unix::UnixReady;
195 ///
196 /// let ready = UnixReady::error();
197 ///
198 /// assert!(ready.is_error());
199 /// ```
200 ///
201 /// [`Poll`]: ../struct.Poll.html
202 /// [readiness]: ../struct.Poll.html#readiness-operations
203 #[inline]
error() -> UnixReady204 pub fn error() -> UnixReady {
205 UnixReady(ready_from_usize(ERROR))
206 }
207
208 /// Returns a `Ready` representing HUP readiness.
209 ///
210 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
211 /// connection, or shut down the writing half of the connection.
212 ///
213 /// **Note that only readable and writable readiness is guaranteed to be
214 /// supported on all platforms**. This means that `hup` readiness
215 /// should be treated as a hint. For more details, see [readiness] in the
216 /// poll documentation. It is also unclear if HUP readiness will remain in 0.7. See
217 /// [here][issue-941].
218 ///
219 /// See [`Poll`] for more documentation on polling.
220 ///
221 /// # Examples
222 ///
223 /// ```
224 /// use mio::unix::UnixReady;
225 ///
226 /// let ready = UnixReady::hup();
227 ///
228 /// assert!(ready.is_hup());
229 /// ```
230 ///
231 /// [`Poll`]: ../struct.Poll.html
232 /// [readiness]: ../struct.Poll.html#readiness-operations
233 /// [issue-941]: https://github.com/tokio-rs/mio/issues/941
234 #[inline]
hup() -> UnixReady235 pub fn hup() -> UnixReady {
236 UnixReady(ready_from_usize(HUP))
237 }
238
239 /// Returns a `Ready` representing LIO completion readiness
240 ///
241 /// See [`Poll`] for more documentation on polling.
242 ///
243 /// # Examples
244 ///
245 /// ```
246 /// use mio::unix::UnixReady;
247 ///
248 /// let ready = UnixReady::lio();
249 ///
250 /// assert!(ready.is_lio());
251 /// ```
252 ///
253 /// [`Poll`]: struct.Poll.html
254 #[inline]
255 #[cfg(any(target_os = "freebsd"))]
lio() -> UnixReady256 pub fn lio() -> UnixReady {
257 UnixReady(ready_from_usize(LIO))
258 }
259
260 /// Returns a `Ready` representing priority (`EPOLLPRI`) readiness
261 ///
262 /// See [`Poll`] for more documentation on polling.
263 ///
264 /// # Examples
265 ///
266 /// ```
267 /// use mio::unix::UnixReady;
268 ///
269 /// let ready = UnixReady::priority();
270 ///
271 /// assert!(ready.is_priority());
272 /// ```
273 ///
274 /// [`Poll`]: struct.Poll.html
275 #[inline]
276 #[cfg(any(
277 target_os = "android",
278 target_os = "illumos",
279 target_os = "linux",
280 target_os = "solaris"
281 ))]
priority() -> UnixReady282 pub fn priority() -> UnixReady {
283 UnixReady(ready_from_usize(PRI))
284 }
285
286 /// Returns true if `Ready` contains AIO readiness
287 ///
288 /// See [`Poll`] for more documentation on polling.
289 ///
290 /// # Examples
291 ///
292 /// ```
293 /// use mio::unix::UnixReady;
294 ///
295 /// let ready = UnixReady::aio();
296 ///
297 /// assert!(ready.is_aio());
298 /// ```
299 ///
300 /// [`Poll`]: ../struct.Poll.html
301 #[inline]
302 #[cfg(any(target_os = "dragonfly",
303 target_os = "freebsd", target_os = "ios", target_os = "macos"))]
is_aio(&self) -> bool304 pub fn is_aio(&self) -> bool {
305 self.contains(ready_from_usize(AIO))
306 }
307
308 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
309 #[cfg(feature = "with-deprecated")]
310 #[cfg(not(any(target_os = "dragonfly",
311 target_os = "freebsd", target_os = "ios", target_os = "macos")))]
312 #[doc(hidden)]
is_aio(&self) -> bool313 pub fn is_aio(&self) -> bool {
314 false
315 }
316
317 /// Returns true if the value includes error readiness
318 ///
319 /// **Note that only readable and writable readiness is guaranteed to be
320 /// supported on all platforms**. This means that `error` readiness should
321 /// be treated as a hint. For more details, see [readiness] in the poll
322 /// documentation.
323 ///
324 /// See [`Poll`] for more documentation on polling.
325 ///
326 /// # Examples
327 ///
328 /// ```
329 /// use mio::unix::UnixReady;
330 ///
331 /// let ready = UnixReady::error();
332 ///
333 /// assert!(ready.is_error());
334 /// ```
335 ///
336 /// [`Poll`]: ../struct.Poll.html
337 /// [readiness]: ../struct.Poll.html#readiness-operations
338 #[inline]
is_error(&self) -> bool339 pub fn is_error(&self) -> bool {
340 self.contains(ready_from_usize(ERROR))
341 }
342
343 /// Returns true if the value includes HUP readiness
344 ///
345 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
346 /// connection, or shut down the writing half of the connection.
347 ///
348 /// **Note that only readable and writable readiness is guaranteed to be
349 /// supported on all platforms**. This means that `hup` readiness
350 /// should be treated as a hint. For more details, see [readiness] in the
351 /// poll documentation.
352 ///
353 /// See [`Poll`] for more documentation on polling.
354 ///
355 /// # Examples
356 ///
357 /// ```
358 /// use mio::unix::UnixReady;
359 ///
360 /// let ready = UnixReady::hup();
361 ///
362 /// assert!(ready.is_hup());
363 /// ```
364 ///
365 /// [`Poll`]: ../struct.Poll.html
366 /// [readiness]: ../struct.Poll.html#readiness-operations
367 #[inline]
is_hup(&self) -> bool368 pub fn is_hup(&self) -> bool {
369 self.contains(ready_from_usize(HUP))
370 }
371
372 /// Returns true if `Ready` contains LIO 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::lio();
382 ///
383 /// assert!(ready.is_lio());
384 /// ```
385 #[inline]
386 #[cfg(any(target_os = "freebsd"))]
is_lio(&self) -> bool387 pub fn is_lio(&self) -> bool {
388 self.contains(ready_from_usize(LIO))
389 }
390
391 /// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
392 ///
393 /// See [`Poll`] for more documentation on polling.
394 ///
395 /// # Examples
396 ///
397 /// ```
398 /// use mio::unix::UnixReady;
399 ///
400 /// let ready = UnixReady::priority();
401 ///
402 /// assert!(ready.is_priority());
403 /// ```
404 ///
405 /// [`Poll`]: struct.Poll.html
406 #[inline]
407 #[cfg(any(
408 target_os = "android",
409 target_os = "illumos",
410 target_os = "linux",
411 target_os = "solaris"
412 ))]
is_priority(&self) -> bool413 pub fn is_priority(&self) -> bool {
414 self.contains(ready_from_usize(PRI))
415 }
416 }
417
418 impl From<Ready> for UnixReady {
from(src: Ready) -> UnixReady419 fn from(src: Ready) -> UnixReady {
420 UnixReady(src)
421 }
422 }
423
424 impl From<UnixReady> for Ready {
from(src: UnixReady) -> Ready425 fn from(src: UnixReady) -> Ready {
426 src.0
427 }
428 }
429
430 impl ops::Deref for UnixReady {
431 type Target = Ready;
432
deref(&self) -> &Ready433 fn deref(&self) -> &Ready {
434 &self.0
435 }
436 }
437
438 impl ops::DerefMut for UnixReady {
deref_mut(&mut self) -> &mut Ready439 fn deref_mut(&mut self) -> &mut Ready {
440 &mut self.0
441 }
442 }
443
444 impl ops::BitOr for UnixReady {
445 type Output = UnixReady;
446
447 #[inline]
bitor(self, other: UnixReady) -> UnixReady448 fn bitor(self, other: UnixReady) -> UnixReady {
449 (self.0 | other.0).into()
450 }
451 }
452
453 impl ops::BitXor for UnixReady {
454 type Output = UnixReady;
455
456 #[inline]
bitxor(self, other: UnixReady) -> UnixReady457 fn bitxor(self, other: UnixReady) -> UnixReady {
458 (self.0 ^ other.0).into()
459 }
460 }
461
462 impl ops::BitAnd for UnixReady {
463 type Output = UnixReady;
464
465 #[inline]
bitand(self, other: UnixReady) -> UnixReady466 fn bitand(self, other: UnixReady) -> UnixReady {
467 (self.0 & other.0).into()
468 }
469 }
470
471 impl ops::Sub for UnixReady {
472 type Output = UnixReady;
473
474 #[inline]
sub(self, other: UnixReady) -> UnixReady475 fn sub(self, other: UnixReady) -> UnixReady {
476 ready_from_usize(ready_as_usize(self.0) & !ready_as_usize(other.0)).into()
477 }
478 }
479
480 #[deprecated(since = "0.6.10", note = "removed")]
481 #[cfg(feature = "with-deprecated")]
482 #[doc(hidden)]
483 impl ops::Not for UnixReady {
484 type Output = UnixReady;
485
486 #[inline]
not(self) -> UnixReady487 fn not(self) -> UnixReady {
488 (!self.0).into()
489 }
490 }
491
492 impl fmt::Debug for UnixReady {
fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result493 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
494 let mut one = false;
495 let flags = [
496 (UnixReady(Ready::readable()), "Readable"),
497 (UnixReady(Ready::writable()), "Writable"),
498 (UnixReady::error(), "Error"),
499 (UnixReady::hup(), "Hup"),
500 #[allow(deprecated)]
501 (UnixReady::aio(), "Aio"),
502 #[cfg(any(
503 target_os = "android",
504 target_os = "illumos",
505 target_os = "linux",
506 target_os = "solaris"
507 ))]
508 (UnixReady::priority(), "Priority"),
509 ];
510
511 for &(flag, msg) in &flags {
512 if self.contains(flag) {
513 if one { write!(fmt, " | ")? }
514 write!(fmt, "{}", msg)?;
515
516 one = true
517 }
518 }
519
520 if !one {
521 fmt.write_str("(empty)")?;
522 }
523
524 Ok(())
525 }
526 }
527