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