1 | #![cfg_attr (not(feature = "net" ), allow(unreachable_pub))] |
2 | |
3 | use crate::io::interest::Interest; |
4 | |
5 | use std::fmt; |
6 | use std::ops; |
7 | |
8 | const READABLE: usize = 0b0_01; |
9 | const WRITABLE: usize = 0b0_10; |
10 | const READ_CLOSED: usize = 0b0_0100; |
11 | const WRITE_CLOSED: usize = 0b0_1000; |
12 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
13 | const PRIORITY: usize = 0b1_0000; |
14 | const 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)] |
21 | pub struct Ready(usize); |
22 | |
23 | impl 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 | |
273 | impl 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 | |
282 | impl ops::BitOrAssign<Ready> for Ready { |
283 | #[inline ] |
284 | fn bitor_assign(&mut self, other: Ready) { |
285 | self.0 |= other.0; |
286 | } |
287 | } |
288 | |
289 | impl 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 | |
298 | impl 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 | |
307 | impl 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 | |