1 #![cfg_attr(not(feature = "net"), allow(dead_code, unreachable_pub))]
2 
3 use crate::io::ready::Ready;
4 
5 use std::fmt;
6 use std::ops;
7 
8 // These must be unique.
9 // same as mio
10 const READABLE: usize = 0b0001;
11 const WRITABLE: usize = 0b0010;
12 // The following are not available on all platforms.
13 #[cfg(target_os = "freebsd")]
14 const AIO: usize = 0b0100;
15 #[cfg(target_os = "freebsd")]
16 const LIO: usize = 0b1000;
17 #[cfg(any(target_os = "linux", target_os = "android"))]
18 const PRIORITY: usize = 0b0001_0000;
19 // error is available on all platforms, but behavior is platform-specific
20 // mio does not have this interest
21 const 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)]
29 pub struct Interest(usize);
30 
31 impl 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     /// ```
is_readable(self) -> bool86     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     /// ```
is_writable(self) -> bool103     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     /// ```
is_error(self) -> bool120     pub const fn is_error(self) -> bool {
121         self.0 & ERROR != 0
122     }
123 
124     #[cfg(target_os = "freebsd")]
is_aio(self) -> bool125     const fn is_aio(self) -> bool {
126         self.0 & AIO != 0
127     }
128 
129     #[cfg(target_os = "freebsd")]
is_lio(self) -> bool130     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"))))]
is_priority(self) -> bool149     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"]
add(self, other: Interest) -> Interest167     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"]
remove(self, other: Interest) -> Option<Interest>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.
to_mio(self) -> mio::Interest206     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 
mask(self) -> Ready258     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 
270 impl ops::BitOr for Interest {
271     type Output = Self;
272 
273     #[inline]
bitor(self, other: Self) -> Self274     fn bitor(self, other: Self) -> Self {
275         self.add(other)
276     }
277 }
278 
279 impl ops::BitOrAssign for Interest {
280     #[inline]
bitor_assign(&mut self, other: Self)281     fn bitor_assign(&mut self, other: Self) {
282         *self = *self | other;
283     }
284 }
285 
286 impl fmt::Debug for Interest {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result287     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