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}
323