1 use crate::{sys, Token};
2 
3 use std::fmt;
4 
5 /// A readiness event.
6 ///
7 /// `Event` is a readiness state paired with a [`Token`]. It is returned by
8 /// [`Poll::poll`].
9 ///
10 /// For more documentation on polling and events, see [`Poll`].
11 ///
12 /// [`Poll::poll`]: ../struct.Poll.html#method.poll
13 /// [`Poll`]: ../struct.Poll.html
14 /// [`Token`]: ../struct.Token.html
15 #[derive(Clone)]
16 #[repr(transparent)]
17 pub struct Event {
18     inner: sys::Event,
19 }
20 
21 impl Event {
22     /// Returns the event's token.
token(&self) -> Token23     pub fn token(&self) -> Token {
24         sys::event::token(&self.inner)
25     }
26 
27     /// Returns true if the event contains readable readiness.
is_readable(&self) -> bool28     pub fn is_readable(&self) -> bool {
29         sys::event::is_readable(&self.inner)
30     }
31 
32     /// Returns true if the event contains writable readiness.
is_writable(&self) -> bool33     pub fn is_writable(&self) -> bool {
34         sys::event::is_writable(&self.inner)
35     }
36 
37     /// Returns true if the event contains error readiness.
38     ///
39     /// Error events occur when the socket enters an error state. In this case,
40     /// the socket will also receive a readable or writable event. Reading or
41     /// writing to the socket will result in an error.
42     ///
43     /// # Notes
44     ///
45     /// Method is available on all platforms, but not all platforms trigger the
46     /// error event.
47     ///
48     /// The table below shows what flags are checked on what OS.
49     ///
50     /// | [OS selector] | Flag(s) checked |
51     /// |---------------|-----------------|
52     /// | [epoll]       | `EPOLLERR`      |
53     /// | [kqueue]      | `EV_ERROR` and `EV_EOF` with `fflags` set to `0`. |
54     ///
55     /// [OS selector]: ../struct.Poll.html#implementation-notes
56     /// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
57     /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
is_error(&self) -> bool58     pub fn is_error(&self) -> bool {
59         sys::event::is_error(&self.inner)
60     }
61 
62     /// Returns true if the event contains read closed readiness.
63     ///
64     /// # Notes
65     ///
66     /// Read closed readiness can be expected after any of the following have
67     /// occurred:
68     /// * The local stream has shutdown the read half of its socket
69     /// * The local stream has shutdown both the read half and the write half
70     ///   of its socket
71     /// * The peer stream has shutdown the write half its socket; this sends a
72     ///   `FIN` packet that has been received by the local stream
73     ///
74     /// Method is a best effort implementation. While some platforms may not
75     /// return readiness when read half is closed, it is guaranteed that
76     /// false-positives will not occur.
77     ///
78     /// The table below shows what flags are checked on what OS.
79     ///
80     /// | [OS selector] | Flag(s) checked |
81     /// |---------------|-----------------|
82     /// | [epoll]       | `EPOLLHUP`, or  |
83     /// |               | `EPOLLIN` and `EPOLLRDHUP` |
84     /// | [kqueue]      | `EV_EOF`        |
85     ///
86     /// [OS selector]: ../struct.Poll.html#implementation-notes
87     /// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
88     /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
is_read_closed(&self) -> bool89     pub fn is_read_closed(&self) -> bool {
90         sys::event::is_read_closed(&self.inner)
91     }
92 
93     /// Returns true if the event contains write closed readiness.
94     ///
95     /// # Notes
96     ///
97     /// On [epoll] this is essentially a check for `EPOLLHUP` flag as the
98     /// local stream shutting down its write half does not trigger this event.
99     ///
100     /// On [kqueue] the local stream shutting down the write half of its
101     /// socket will trigger this event.
102     ///
103     /// Method is a best effort implementation. While some platforms may not
104     /// return readiness when write half is closed, it is guaranteed that
105     /// false-positives will not occur.
106     ///
107     /// The table below shows what flags are checked on what OS.
108     ///
109     /// | [OS selector] | Flag(s) checked |
110     /// |---------------|-----------------|
111     /// | [epoll]       | `EPOLLHUP`, or  |
112     /// |               | only `EPOLLERR`, or |
113     /// |               | `EPOLLOUT` and `EPOLLERR` |
114     /// | [kqueue]      | `EV_EOF`        |
115     ///
116     /// [OS selector]: ../struct.Poll.html#implementation-notes
117     /// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
118     /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
is_write_closed(&self) -> bool119     pub fn is_write_closed(&self) -> bool {
120         sys::event::is_write_closed(&self.inner)
121     }
122 
123     /// Returns true if the event contains priority readiness.
124     ///
125     /// # Notes
126     ///
127     /// Method is available on all platforms, but not all platforms trigger the
128     /// priority event.
129     ///
130     /// The table below shows what flags are checked on what OS.
131     ///
132     /// | [OS selector] | Flag(s) checked |
133     /// |---------------|-----------------|
134     /// | [epoll]       | `EPOLLPRI`      |
135     /// | [kqueue]      | *Not supported* |
136     ///
137     /// [OS selector]: ../struct.Poll.html#implementation-notes
138     /// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
139     /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
140     #[inline]
is_priority(&self) -> bool141     pub fn is_priority(&self) -> bool {
142         sys::event::is_priority(&self.inner)
143     }
144 
145     /// Returns true if the event contains AIO readiness.
146     ///
147     /// # Notes
148     ///
149     /// Method is available on all platforms, but not all platforms support AIO.
150     ///
151     /// The table below shows what flags are checked on what OS.
152     ///
153     /// | [OS selector] | Flag(s) checked |
154     /// |---------------|-----------------|
155     /// | [epoll]       | *Not supported* |
156     /// | [kqueue]<sup>1</sup> | `EVFILT_AIO` |
157     ///
158     /// 1: Only supported on DragonFly BSD, FreeBSD, iOS and macOS.
159     ///
160     /// [OS selector]: ../struct.Poll.html#implementation-notes
161     /// [epoll]: http://man7.org/linux/man-pages/man7/epoll.7.html
162     /// [kqueue]: https://www.freebsd.org/cgi/man.cgi?query=kqueue&sektion=2
is_aio(&self) -> bool163     pub fn is_aio(&self) -> bool {
164         sys::event::is_aio(&self.inner)
165     }
166 
167     /// Returns true if the event contains LIO readiness.
168     ///
169     /// # Notes
170     ///
171     /// Method is available on all platforms, but only FreeBSD supports LIO. On
172     /// FreeBSD this method checks the `EVFILT_LIO` flag.
is_lio(&self) -> bool173     pub fn is_lio(&self) -> bool {
174         sys::event::is_lio(&self.inner)
175     }
176 
177     /// Create a reference to an `Event` from a platform specific event.
from_sys_event_ref(sys_event: &sys::Event) -> &Event178     pub(crate) fn from_sys_event_ref(sys_event: &sys::Event) -> &Event {
179         unsafe {
180             // This is safe because the memory layout of `Event` is
181             // the same as `sys::Event` due to the `repr(transparent)` attribute.
182             &*(sys_event as *const sys::Event as *const Event)
183         }
184     }
185 }
186 
187 /// When the [alternate] flag is enabled this will print platform specific
188 /// details, for example the fields of the `kevent` structure on platforms that
189 /// use `kqueue(2)`. Note however that the output of this implementation is
190 /// **not** consider a part of the stable API.
191 ///
192 /// [alternate]: fmt::Formatter::alternate
193 impl fmt::Debug for Event {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result194     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195         let alternate = f.alternate();
196         let mut d = f.debug_struct("Event");
197         d.field("token", &self.token())
198             .field("readable", &self.is_readable())
199             .field("writable", &self.is_writable())
200             .field("error", &self.is_error())
201             .field("read_closed", &self.is_read_closed())
202             .field("write_closed", &self.is_write_closed())
203             .field("priority", &self.is_priority())
204             .field("aio", &self.is_aio())
205             .field("lio", &self.is_lio());
206 
207         if alternate {
208             struct EventDetails<'a>(&'a sys::Event);
209 
210             impl<'a> fmt::Debug for EventDetails<'a> {
211                 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
212                     sys::event::debug_details(f, self.0)
213                 }
214             }
215 
216             d.field("details", &EventDetails(&self.inner)).finish()
217         } else {
218             d.finish()
219         }
220     }
221 }
222