corcovado/sys/unix/
ready.rs

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