• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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());
add(self, other: Interest) -> Interest166     pub const fn add(self, other: Interest) -> Interest {
167         Self(self.0 | other.0)
168     }
169 
170     // This function must be crate-private to avoid exposing a `mio` dependency.
to_mio(self) -> mio::Interest171     pub(crate) fn to_mio(self) -> mio::Interest {
172         fn mio_add(wrapped: &mut Option<mio::Interest>, add: mio::Interest) {
173             match wrapped {
174                 Some(inner) => *inner |= add,
175                 None => *wrapped = Some(add),
176             }
177         }
178 
179         // mio does not allow and empty interest, so use None for empty
180         let mut mio = None;
181 
182         if self.is_readable() {
183             mio_add(&mut mio, mio::Interest::READABLE);
184         }
185 
186         if self.is_writable() {
187             mio_add(&mut mio, mio::Interest::WRITABLE);
188         }
189 
190         #[cfg(any(target_os = "linux", target_os = "android"))]
191         if self.is_priority() {
192             mio_add(&mut mio, mio::Interest::PRIORITY);
193         }
194 
195         #[cfg(target_os = "freebsd")]
196         if self.is_aio() {
197             mio_add(&mut mio, mio::Interest::AIO);
198         }
199 
200         #[cfg(target_os = "freebsd")]
201         if self.is_lio() {
202             mio_add(&mut mio, mio::Interest::LIO);
203         }
204 
205         if self.is_error() {
206             // There is no error interest in mio, because error events are always reported.
207             // But mio interests cannot be empty and an interest is needed just for the registeration.
208             //
209             // read readiness is filtered out in `Interest::mask` or `Ready::from_interest` if
210             // the read interest was not specified by the user.
211             mio_add(&mut mio, mio::Interest::READABLE);
212         }
213 
214         // the default `mio::Interest::READABLE` should never be used in practice. Either
215         //
216         // - at least one tokio interest with a mio counterpart was used
217         // - only the error tokio interest was specified
218         //
219         // in both cases, `mio` is Some already
220         mio.unwrap_or(mio::Interest::READABLE)
221     }
222 
mask(self) -> Ready223     pub(crate) fn mask(self) -> Ready {
224         match self {
225             Interest::READABLE => Ready::READABLE | Ready::READ_CLOSED,
226             Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED,
227             #[cfg(any(target_os = "linux", target_os = "android"))]
228             Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED,
229             Interest::ERROR => Ready::ERROR,
230             _ => Ready::EMPTY,
231         }
232     }
233 }
234 
235 impl ops::BitOr for Interest {
236     type Output = Self;
237 
238     #[inline]
bitor(self, other: Self) -> Self239     fn bitor(self, other: Self) -> Self {
240         self.add(other)
241     }
242 }
243 
244 impl ops::BitOrAssign for Interest {
245     #[inline]
bitor_assign(&mut self, other: Self)246     fn bitor_assign(&mut self, other: Self) {
247         *self = *self | other
248     }
249 }
250 
251 impl fmt::Debug for Interest {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result252     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
253         let mut separator = false;
254 
255         if self.is_readable() {
256             if separator {
257                 write!(fmt, " | ")?;
258             }
259             write!(fmt, "READABLE")?;
260             separator = true;
261         }
262 
263         if self.is_writable() {
264             if separator {
265                 write!(fmt, " | ")?;
266             }
267             write!(fmt, "WRITABLE")?;
268             separator = true;
269         }
270 
271         #[cfg(any(target_os = "linux", target_os = "android"))]
272         if self.is_priority() {
273             if separator {
274                 write!(fmt, " | ")?;
275             }
276             write!(fmt, "PRIORITY")?;
277             separator = true;
278         }
279 
280         #[cfg(target_os = "freebsd")]
281         if self.is_aio() {
282             if separator {
283                 write!(fmt, " | ")?;
284             }
285             write!(fmt, "AIO")?;
286             separator = true;
287         }
288 
289         #[cfg(target_os = "freebsd")]
290         if self.is_lio() {
291             if separator {
292                 write!(fmt, " | ")?;
293             }
294             write!(fmt, "LIO")?;
295             separator = true;
296         }
297 
298         if self.is_error() {
299             if separator {
300                 write!(fmt, " | ")?;
301             }
302             write!(fmt, "ERROR")?;
303             separator = true;
304         }
305 
306         let _ = separator;
307 
308         Ok(())
309     }
310 }
311