1#![cfg_attr(not(feature = "net"), allow(dead_code, unreachable_pub))]
2
3use crate::io::ready::Ready;
4
5use std::fmt;
6use std::ops;
7
8// These must be unique.
9// same as mio
10const READABLE: usize = 0b0001;
11const WRITABLE: usize = 0b0010;
12// The following are not available on all platforms.
13#[cfg(target_os = "freebsd")]
14const AIO: usize = 0b0100;
15#[cfg(target_os = "freebsd")]
16const LIO: usize = 0b1000;
17#[cfg(any(target_os = "linux", target_os = "android"))]
18const PRIORITY: usize = 0b0001_0000;
19// error is available on all platforms, but behavior is platform-specific
20// mio does not have this interest
21const ERROR: usize = 0b0010_0000;
22
23/// Readiness event interest.
24///
25/// Specifies the readiness events the caller is interested in when awaiting on
26/// I/O resource readiness states.
27#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
28#[derive(Clone, Copy, Eq, PartialEq)]
29pub struct Interest(usize);
30
31impl Interest {
32 // The non-FreeBSD definitions in this block are active only when
33 // building documentation.
34 cfg_aio! {
35 /// Interest for POSIX AIO.
36 #[cfg(target_os = "freebsd")]
37 pub const AIO: Interest = Interest(AIO);
38
39 /// Interest for POSIX AIO.
40 #[cfg(not(target_os = "freebsd"))]
41 pub const AIO: Interest = Interest(READABLE);
42
43 /// Interest for POSIX AIO `lio_listio` events.
44 #[cfg(target_os = "freebsd")]
45 pub const LIO: Interest = Interest(LIO);
46
47 /// Interest for POSIX AIO `lio_listio` events.
48 #[cfg(not(target_os = "freebsd"))]
49 pub const LIO: Interest = Interest(READABLE);
50 }
51
52 /// Interest in all readable events.
53 ///
54 /// Readable interest includes read-closed events.
55 pub const READABLE: Interest = Interest(READABLE);
56
57 /// Interest in all writable events.
58 ///
59 /// Writable interest includes write-closed events.
60 pub const WRITABLE: Interest = Interest(WRITABLE);
61
62 /// Interest in error events.
63 ///
64 /// Passes error interest to the underlying OS selector.
65 /// Behavior is platform-specific, read your platform's documentation.
66 pub const ERROR: Interest = Interest(ERROR);
67
68 /// Returns a `Interest` set representing priority completion interests.
69 #[cfg(any(target_os = "linux", target_os = "android"))]
70 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
71 pub const PRIORITY: Interest = Interest(PRIORITY);
72
73 /// Returns true if the value includes readable interest.
74 ///
75 /// # Examples
76 ///
77 /// ```
78 /// use tokio::io::Interest;
79 ///
80 /// assert!(Interest::READABLE.is_readable());
81 /// assert!(!Interest::WRITABLE.is_readable());
82 ///
83 /// let both = Interest::READABLE | Interest::WRITABLE;
84 /// assert!(both.is_readable());
85 /// ```
86 pub const fn is_readable(self) -> bool {
87 self.0 & READABLE != 0
88 }
89
90 /// Returns true if the value includes writable interest.
91 ///
92 /// # Examples
93 ///
94 /// ```
95 /// use tokio::io::Interest;
96 ///
97 /// assert!(!Interest::READABLE.is_writable());
98 /// assert!(Interest::WRITABLE.is_writable());
99 ///
100 /// let both = Interest::READABLE | Interest::WRITABLE;
101 /// assert!(both.is_writable());
102 /// ```
103 pub const fn is_writable(self) -> bool {
104 self.0 & WRITABLE != 0
105 }
106
107 /// Returns true if the value includes error interest.
108 ///
109 /// # Examples
110 ///
111 /// ```
112 /// use tokio::io::Interest;
113 ///
114 /// assert!(Interest::ERROR.is_error());
115 /// assert!(!Interest::WRITABLE.is_error());
116 ///
117 /// let combined = Interest::READABLE | Interest::ERROR;
118 /// assert!(combined.is_error());
119 /// ```
120 pub const fn is_error(self) -> bool {
121 self.0 & ERROR != 0
122 }
123
124 #[cfg(target_os = "freebsd")]
125 const fn is_aio(self) -> bool {
126 self.0 & AIO != 0
127 }
128
129 #[cfg(target_os = "freebsd")]
130 const fn is_lio(self) -> bool {
131 self.0 & LIO != 0
132 }
133
134 /// Returns true if the value includes priority interest.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use tokio::io::Interest;
140 ///
141 /// assert!(!Interest::READABLE.is_priority());
142 /// assert!(Interest::PRIORITY.is_priority());
143 ///
144 /// let both = Interest::READABLE | Interest::PRIORITY;
145 /// assert!(both.is_priority());
146 /// ```
147 #[cfg(any(target_os = "linux", target_os = "android"))]
148 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
149 pub const fn is_priority(self) -> bool {
150 self.0 & PRIORITY != 0
151 }
152
153 /// Add together two `Interest` values.
154 ///
155 /// This function works from a `const` context.
156 ///
157 /// # Examples
158 ///
159 /// ```
160 /// use tokio::io::Interest;
161 ///
162 /// const BOTH: Interest = Interest::READABLE.add(Interest::WRITABLE);
163 ///
164 /// assert!(BOTH.is_readable());
165 /// assert!(BOTH.is_writable());
166 #[must_use = "this returns the result of the operation, without modifying the original"]
167 pub const fn add(self, other: Interest) -> Interest {
168 Self(self.0 | other.0)
169 }
170
171 /// Remove `Interest` from `self`.
172 ///
173 /// Interests present in `other` but *not* in `self` are ignored.
174 ///
175 /// Returns `None` if the set would be empty after removing `Interest`.
176 ///
177 /// # Examples
178 ///
179 /// ```
180 /// use tokio::io::Interest;
181 ///
182 /// const RW_INTEREST: Interest = Interest::READABLE.add(Interest::WRITABLE);
183 ///
184 /// let w_interest = RW_INTEREST.remove(Interest::READABLE).unwrap();
185 /// assert!(!w_interest.is_readable());
186 /// assert!(w_interest.is_writable());
187 ///
188 /// // Removing all interests from the set returns `None`.
189 /// assert_eq!(w_interest.remove(Interest::WRITABLE), None);
190 ///
191 /// // Remove all interests at once.
192 /// assert_eq!(RW_INTEREST.remove(RW_INTEREST), None);
193 /// ```
194 #[must_use = "this returns the result of the operation, without modifying the original"]
195 pub fn remove(self, other: Interest) -> Option<Interest> {
196 let value = self.0 & !other.0;
197
198 if value != 0 {
199 Some(Self(value))
200 } else {
201 None
202 }
203 }
204
205 // This function must be crate-private to avoid exposing a `mio` dependency.
206 pub(crate) fn to_mio(self) -> mio::Interest {
207 fn mio_add(wrapped: &mut Option<mio::Interest>, add: mio::Interest) {
208 match wrapped {
209 Some(inner) => *inner |= add,
210 None => *wrapped = Some(add),
211 }
212 }
213
214 // mio does not allow and empty interest, so use None for empty
215 let mut mio = None;
216
217 if self.is_readable() {
218 mio_add(&mut mio, mio::Interest::READABLE);
219 }
220
221 if self.is_writable() {
222 mio_add(&mut mio, mio::Interest::WRITABLE);
223 }
224
225 #[cfg(any(target_os = "linux", target_os = "android"))]
226 if self.is_priority() {
227 mio_add(&mut mio, mio::Interest::PRIORITY);
228 }
229
230 #[cfg(target_os = "freebsd")]
231 if self.is_aio() {
232 mio_add(&mut mio, mio::Interest::AIO);
233 }
234
235 #[cfg(target_os = "freebsd")]
236 if self.is_lio() {
237 mio_add(&mut mio, mio::Interest::LIO);
238 }
239
240 if self.is_error() {
241 // There is no error interest in mio, because error events are always reported.
242 // But mio interests cannot be empty and an interest is needed just for the registration.
243 //
244 // read readiness is filtered out in `Interest::mask` or `Ready::from_interest` if
245 // the read interest was not specified by the user.
246 mio_add(&mut mio, mio::Interest::READABLE);
247 }
248
249 // the default `mio::Interest::READABLE` should never be used in practice. Either
250 //
251 // - at least one tokio interest with a mio counterpart was used
252 // - only the error tokio interest was specified
253 //
254 // in both cases, `mio` is Some already
255 mio.unwrap_or(mio::Interest::READABLE)
256 }
257
258 pub(crate) fn mask(self) -> Ready {
259 match self {
260 Interest::READABLE => Ready::READABLE | Ready::READ_CLOSED,
261 Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED,
262 #[cfg(any(target_os = "linux", target_os = "android"))]
263 Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED,
264 Interest::ERROR => Ready::ERROR,
265 _ => Ready::EMPTY,
266 }
267 }
268}
269
270impl ops::BitOr for Interest {
271 type Output = Self;
272
273 #[inline]
274 fn bitor(self, other: Self) -> Self {
275 self.add(other)
276 }
277}
278
279impl ops::BitOrAssign for Interest {
280 #[inline]
281 fn bitor_assign(&mut self, other: Self) {
282 *self = *self | other;
283 }
284}
285
286impl fmt::Debug for Interest {
287 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
288 let mut separator = false;
289
290 if self.is_readable() {
291 if separator {
292 write!(fmt, " | ")?;
293 }
294 write!(fmt, "READABLE")?;
295 separator = true;
296 }
297
298 if self.is_writable() {
299 if separator {
300 write!(fmt, " | ")?;
301 }
302 write!(fmt, "WRITABLE")?;
303 separator = true;
304 }
305
306 #[cfg(any(target_os = "linux", target_os = "android"))]
307 if self.is_priority() {
308 if separator {
309 write!(fmt, " | ")?;
310 }
311 write!(fmt, "PRIORITY")?;
312 separator = true;
313 }
314
315 #[cfg(target_os = "freebsd")]
316 if self.is_aio() {
317 if separator {
318 write!(fmt, " | ")?;
319 }
320 write!(fmt, "AIO")?;
321 separator = true;
322 }
323
324 #[cfg(target_os = "freebsd")]
325 if self.is_lio() {
326 if separator {
327 write!(fmt, " | ")?;
328 }
329 write!(fmt, "LIO")?;
330 separator = true;
331 }
332
333 if self.is_error() {
334 if separator {
335 write!(fmt, " | ")?;
336 }
337 write!(fmt, "ERROR")?;
338 separator = true;
339 }
340
341 let _ = separator;
342
343 Ok(())
344 }
345}
346