1 | #![cfg_attr (not(feature = "net" ), allow(unreachable_pub))] |
2 | |
3 | use std::fmt; |
4 | use std::ops; |
5 | |
6 | const READABLE: usize = 0b0_01; |
7 | const WRITABLE: usize = 0b0_10; |
8 | const READ_CLOSED: usize = 0b0_0100; |
9 | const WRITE_CLOSED: usize = 0b0_1000; |
10 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
11 | const 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)] |
18 | pub struct Ready(usize); |
19 | |
20 | impl 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 | |
213 | cfg_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 | |
249 | impl 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 | |
258 | impl ops::BitOrAssign<Ready> for Ready { |
259 | #[inline ] |
260 | fn bitor_assign(&mut self, other: Ready) { |
261 | self.0 |= other.0; |
262 | } |
263 | } |
264 | |
265 | impl 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 | |
274 | impl 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 | |
283 | impl 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 | |