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