mio/event/
event.rs

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