tokio/io/
ready.rs

1#![cfg_attr(not(feature = "net"), allow(unreachable_pub))]
2
3use crate::io::interest::Interest;
4
5use std::fmt;
6use std::ops;
7
8const READABLE: usize = 0b0_01;
9const WRITABLE: usize = 0b0_10;
10const READ_CLOSED: usize = 0b0_0100;
11const WRITE_CLOSED: usize = 0b0_1000;
12#[cfg(any(target_os = "linux", target_os = "android"))]
13const PRIORITY: usize = 0b1_0000;
14const ERROR: usize = 0b10_0000;
15
16/// Describes the readiness state of an I/O resources.
17///
18/// `Ready` tracks which operation an I/O resource is ready to perform.
19#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
20#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
21pub struct Ready(usize);
22
23impl Ready {
24    /// Returns the empty `Ready` set.
25    pub const EMPTY: Ready = Ready(0);
26
27    /// Returns a `Ready` representing readable readiness.
28    pub const READABLE: Ready = Ready(READABLE);
29
30    /// Returns a `Ready` representing writable readiness.
31    pub const WRITABLE: Ready = Ready(WRITABLE);
32
33    /// Returns a `Ready` representing read closed readiness.
34    pub const READ_CLOSED: Ready = Ready(READ_CLOSED);
35
36    /// Returns a `Ready` representing write closed readiness.
37    pub const WRITE_CLOSED: Ready = Ready(WRITE_CLOSED);
38
39    /// Returns a `Ready` representing priority readiness.
40    #[cfg(any(target_os = "linux", target_os = "android"))]
41    #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
42    pub const PRIORITY: Ready = Ready(PRIORITY);
43
44    /// Returns a `Ready` representing error readiness.
45    pub const ERROR: Ready = Ready(ERROR);
46
47    /// Returns a `Ready` representing readiness for all operations.
48    #[cfg(any(target_os = "linux", target_os = "android"))]
49    pub const ALL: Ready =
50        Ready(READABLE | WRITABLE | READ_CLOSED | WRITE_CLOSED | ERROR | PRIORITY);
51
52    /// Returns a `Ready` representing readiness for all operations.
53    #[cfg(not(any(target_os = "linux", target_os = "android")))]
54    pub const ALL: Ready = Ready(READABLE | WRITABLE | READ_CLOSED | WRITE_CLOSED | ERROR);
55
56    // Must remain crate-private to avoid adding a public dependency on Mio.
57    pub(crate) fn from_mio(event: &mio::event::Event) -> Ready {
58        let mut ready = Ready::EMPTY;
59
60        #[cfg(all(target_os = "freebsd", feature = "net"))]
61        {
62            if event.is_aio() {
63                ready |= Ready::READABLE;
64            }
65
66            if event.is_lio() {
67                ready |= Ready::READABLE;
68            }
69        }
70
71        if event.is_readable() {
72            ready |= Ready::READABLE;
73        }
74
75        if event.is_writable() {
76            ready |= Ready::WRITABLE;
77        }
78
79        if event.is_read_closed() {
80            ready |= Ready::READ_CLOSED;
81        }
82
83        if event.is_write_closed() {
84            ready |= Ready::WRITE_CLOSED;
85        }
86
87        if event.is_error() {
88            ready |= Ready::ERROR;
89        }
90
91        #[cfg(any(target_os = "linux", target_os = "android"))]
92        {
93            if event.is_priority() {
94                ready |= Ready::PRIORITY;
95            }
96        }
97
98        ready
99    }
100
101    /// Returns true if `Ready` is the empty set.
102    ///
103    /// # Examples
104    ///
105    /// ```
106    /// use tokio::io::Ready;
107    ///
108    /// assert!(Ready::EMPTY.is_empty());
109    /// assert!(!Ready::READABLE.is_empty());
110    /// ```
111    pub fn is_empty(self) -> bool {
112        self == Ready::EMPTY
113    }
114
115    /// Returns `true` if the value includes `readable`.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use tokio::io::Ready;
121    ///
122    /// assert!(!Ready::EMPTY.is_readable());
123    /// assert!(Ready::READABLE.is_readable());
124    /// assert!(Ready::READ_CLOSED.is_readable());
125    /// assert!(!Ready::WRITABLE.is_readable());
126    /// ```
127    pub fn is_readable(self) -> bool {
128        self.contains(Ready::READABLE) || self.is_read_closed()
129    }
130
131    /// Returns `true` if the value includes writable `readiness`.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use tokio::io::Ready;
137    ///
138    /// assert!(!Ready::EMPTY.is_writable());
139    /// assert!(!Ready::READABLE.is_writable());
140    /// assert!(Ready::WRITABLE.is_writable());
141    /// assert!(Ready::WRITE_CLOSED.is_writable());
142    /// ```
143    pub fn is_writable(self) -> bool {
144        self.contains(Ready::WRITABLE) || self.is_write_closed()
145    }
146
147    /// Returns `true` if the value includes read-closed `readiness`.
148    ///
149    /// # Examples
150    ///
151    /// ```
152    /// use tokio::io::Ready;
153    ///
154    /// assert!(!Ready::EMPTY.is_read_closed());
155    /// assert!(!Ready::READABLE.is_read_closed());
156    /// assert!(Ready::READ_CLOSED.is_read_closed());
157    /// ```
158    pub fn is_read_closed(self) -> bool {
159        self.contains(Ready::READ_CLOSED)
160    }
161
162    /// Returns `true` if the value includes write-closed `readiness`.
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use tokio::io::Ready;
168    ///
169    /// assert!(!Ready::EMPTY.is_write_closed());
170    /// assert!(!Ready::WRITABLE.is_write_closed());
171    /// assert!(Ready::WRITE_CLOSED.is_write_closed());
172    /// ```
173    pub fn is_write_closed(self) -> bool {
174        self.contains(Ready::WRITE_CLOSED)
175    }
176
177    /// Returns `true` if the value includes priority `readiness`.
178    ///
179    /// # Examples
180    ///
181    /// ```
182    /// use tokio::io::Ready;
183    ///
184    /// assert!(!Ready::EMPTY.is_priority());
185    /// assert!(!Ready::WRITABLE.is_priority());
186    /// assert!(Ready::PRIORITY.is_priority());
187    /// ```
188    #[cfg(any(target_os = "linux", target_os = "android"))]
189    #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
190    pub fn is_priority(self) -> bool {
191        self.contains(Ready::PRIORITY)
192    }
193
194    /// Returns `true` if the value includes error `readiness`.
195    ///
196    /// # Examples
197    ///
198    /// ```
199    /// use tokio::io::Ready;
200    ///
201    /// assert!(!Ready::EMPTY.is_error());
202    /// assert!(!Ready::WRITABLE.is_error());
203    /// assert!(Ready::ERROR.is_error());
204    /// ```
205    pub fn is_error(self) -> bool {
206        self.contains(Ready::ERROR)
207    }
208
209    /// Returns true if `self` is a superset of `other`.
210    ///
211    /// `other` may represent more than one readiness operations, in which case
212    /// the function only returns true if `self` contains all readiness
213    /// specified in `other`.
214    pub(crate) fn contains<T: Into<Self>>(self, other: T) -> bool {
215        let other = other.into();
216        (self & other) == other
217    }
218
219    /// Creates a `Ready` instance using the given `usize` representation.
220    ///
221    /// The `usize` representation must have been obtained from a call to
222    /// `Readiness::as_usize`.
223    ///
224    /// This function is mainly provided to allow the caller to get a
225    /// readiness value from an `AtomicUsize`.
226    pub(crate) fn from_usize(val: usize) -> Ready {
227        Ready(val & Ready::ALL.as_usize())
228    }
229
230    /// Returns a `usize` representation of the `Ready` value.
231    ///
232    /// This function is mainly provided to allow the caller to store a
233    /// readiness value in an `AtomicUsize`.
234    pub(crate) fn as_usize(self) -> usize {
235        self.0
236    }
237
238    pub(crate) fn from_interest(interest: Interest) -> Ready {
239        let mut ready = Ready::EMPTY;
240
241        if interest.is_readable() {
242            ready |= Ready::READABLE;
243            ready |= Ready::READ_CLOSED;
244        }
245
246        if interest.is_writable() {
247            ready |= Ready::WRITABLE;
248            ready |= Ready::WRITE_CLOSED;
249        }
250
251        #[cfg(any(target_os = "linux", target_os = "android"))]
252        if interest.is_priority() {
253            ready |= Ready::PRIORITY;
254            ready |= Ready::READ_CLOSED;
255        }
256
257        if interest.is_error() {
258            ready |= Ready::ERROR;
259        }
260
261        ready
262    }
263
264    pub(crate) fn intersection(self, interest: Interest) -> Ready {
265        Ready(self.0 & Ready::from_interest(interest).0)
266    }
267
268    pub(crate) fn satisfies(self, interest: Interest) -> bool {
269        self.0 & Ready::from_interest(interest).0 != 0
270    }
271}
272
273impl ops::BitOr<Ready> for Ready {
274    type Output = Ready;
275
276    #[inline]
277    fn bitor(self, other: Ready) -> Ready {
278        Ready(self.0 | other.0)
279    }
280}
281
282impl ops::BitOrAssign<Ready> for Ready {
283    #[inline]
284    fn bitor_assign(&mut self, other: Ready) {
285        self.0 |= other.0;
286    }
287}
288
289impl ops::BitAnd<Ready> for Ready {
290    type Output = Ready;
291
292    #[inline]
293    fn bitand(self, other: Ready) -> Ready {
294        Ready(self.0 & other.0)
295    }
296}
297
298impl ops::Sub<Ready> for Ready {
299    type Output = Ready;
300
301    #[inline]
302    fn sub(self, other: Ready) -> Ready {
303        Ready(self.0 & !other.0)
304    }
305}
306
307impl fmt::Debug for Ready {
308    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
309        let mut fmt = fmt.debug_struct("Ready");
310
311        fmt.field("is_readable", &self.is_readable())
312            .field("is_writable", &self.is_writable())
313            .field("is_read_closed", &self.is_read_closed())
314            .field("is_write_closed", &self.is_write_closed())
315            .field("is_error", &self.is_error());
316
317        #[cfg(any(target_os = "linux", target_os = "android"))]
318        fmt.field("is_priority", &self.is_priority());
319
320        fmt.finish()
321    }
322}