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