corcovado/sys/unix/ready.rs
1use event_imp::{ready_as_usize, ready_from_usize, Ready};
2
3use std::fmt;
4use std::ops;
5
6/// Unix specific extensions to `Ready`
7///
8/// Provides additional readiness event kinds that are available on unix
9/// platforms. Unix platforms are able to provide readiness events for
10/// additional socket events, such as HUP and error.
11///
12/// HUP events occur when the remote end of a socket hangs up. In the TCP case,
13/// this occurs when the remote end of a TCP socket shuts down writes.
14///
15/// Error events occur when the socket enters an error state. In this case, the
16/// socket will also receive a readable or writable event. Reading or writing to
17/// the socket will result in an error.
18///
19/// Conversion traits are implemented between `Ready` and `UnixReady`. See the
20/// examples.
21///
22/// For high level documentation on polling and readiness, see [`Poll`].
23///
24/// # Examples
25///
26/// Most of the time, all that is needed is using bit operations
27///
28/// ```
29/// use corcovado::Ready;
30/// use corcovado::unix::UnixReady;
31///
32/// let ready = Ready::readable() | UnixReady::hup();
33///
34/// assert!(ready.is_readable());
35/// assert!(UnixReady::from(ready).is_hup());
36/// ```
37///
38/// Basic conversion between ready types.
39///
40/// ```
41/// use corcovado::Ready;
42/// use corcovado::unix::UnixReady;
43///
44/// // Start with a portable ready
45/// let ready = Ready::readable();
46///
47/// // Convert to a unix ready, adding HUP
48/// let mut unix_ready = UnixReady::from(ready) | UnixReady::hup();
49///
50/// unix_ready.insert(UnixReady::error());
51///
52/// // `unix_ready` maintains readable interest
53/// assert!(unix_ready.is_readable());
54/// assert!(unix_ready.is_hup());
55/// assert!(unix_ready.is_error());
56///
57/// // Convert back to `Ready`
58/// let ready = Ready::from(unix_ready);
59///
60/// // Readable is maintained
61/// assert!(ready.is_readable());
62/// ```
63///
64// Registering readable and error interest on a socket
65//
66// ```
67// # use std::error::Error;
68// # fn try_main() -> Result<(), Box<dyn Error>> {
69// use corcovado::{Ready, Poll, PollOpt, Token};
70// use std::net::TcpStream;
71// use corcovado::unix::UnixReady;
72//
73// let addr = "216.58.193.68:80".parse()?;
74// let socket = TcpStream::connect(&addr)?;
75//
76// let poll = Poll::new()?;
77//
78// poll.register(&socket,
79// Token(0),
80// Ready::readable() | UnixReady::error(),
81// PollOpt::edge())?;
82// # Ok(())
83// # }
84// #
85// # fn main() {
86// # try_main().unwrap();
87// # }
88// ```
89//
90/// [`Poll`]: ../struct.Poll.html
91/// [readiness]: struct.Poll.html#readiness-operations
92#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord)]
93pub struct UnixReady(Ready);
94
95const ERROR: usize = 0b00_0100;
96const HUP: usize = 0b00_1000;
97
98#[cfg(any(
99 target_os = "dragonfly",
100 target_os = "freebsd",
101 target_os = "ios",
102 target_os = "macos"
103))]
104const AIO: usize = 0b01_0000;
105
106#[cfg(not(any(
107 target_os = "dragonfly",
108 target_os = "freebsd",
109 target_os = "ios",
110 target_os = "macos"
111)))]
112const AIO: usize = 0b00_0000;
113
114#[cfg(target_os = "freebsd")]
115const LIO: usize = 0b10_0000;
116
117#[cfg(not(any(target_os = "freebsd")))]
118const LIO: usize = 0b00_0000;
119
120#[cfg(any(
121 target_os = "android",
122 target_os = "illumos",
123 target_os = "linux",
124 target_os = "solaris"
125))]
126const PRI: usize = 0b100_0000;
127
128#[cfg(not(any(
129 target_os = "android",
130 target_os = "illumos",
131 target_os = "linux",
132 target_os = "solaris"
133)))]
134const PRI: usize = 0;
135
136// Export to support `Ready::all`
137pub const READY_ALL: usize = ERROR | HUP | AIO | LIO | PRI;
138
139#[test]
140fn test_ready_all() {
141 let readable = Ready::readable().as_usize();
142 let writable = Ready::writable().as_usize();
143
144 assert_eq!(
145 READY_ALL | readable | writable,
146 ERROR + HUP + AIO + LIO + PRI + readable + writable
147 );
148
149 // Issue #896.
150 #[cfg(any(
151 target_os = "android",
152 target_os = "illumos",
153 target_os = "linux",
154 target_os = "solaris"
155 ))]
156 assert!(!Ready::from(UnixReady::priority()).is_writable());
157}
158
159impl UnixReady {
160 /// Returns a `Ready` representing AIO completion readiness
161 ///
162 /// See [`Poll`] for more documentation on polling.
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use corcovado::unix::UnixReady;
168 ///
169 /// let ready = UnixReady::aio();
170 ///
171 /// assert!(ready.is_aio());
172 /// ```
173 ///
174 /// [`Poll`]: ../struct.Poll.html
175 #[inline]
176 #[cfg(any(
177 target_os = "dragonfly",
178 target_os = "freebsd",
179 target_os = "ios",
180 target_os = "macos"
181 ))]
182 pub fn aio() -> UnixReady {
183 UnixReady(ready_from_usize(AIO))
184 }
185
186 #[cfg(not(any(
187 target_os = "dragonfly",
188 target_os = "freebsd",
189 target_os = "ios",
190 target_os = "macos"
191 )))]
192 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
193 #[doc(hidden)]
194 pub fn aio() -> UnixReady {
195 UnixReady(Ready::empty())
196 }
197
198 /// Returns a `Ready` representing error readiness.
199 ///
200 /// **Note that only readable and writable readiness is guaranteed to be
201 /// supported on all platforms**. This means that `error` readiness
202 /// should be treated as a hint. For more details, see [readiness] in the
203 /// poll documentation.
204 ///
205 /// See [`Poll`] for more documentation on polling.
206 ///
207 /// # Examples
208 ///
209 /// ```
210 /// use corcovado::unix::UnixReady;
211 ///
212 /// let ready = UnixReady::error();
213 ///
214 /// assert!(ready.is_error());
215 /// ```
216 ///
217 /// [`Poll`]: ../struct.Poll.html
218 /// [readiness]: ../struct.Poll.html#readiness-operations
219 #[inline]
220 pub fn error() -> UnixReady {
221 UnixReady(ready_from_usize(ERROR))
222 }
223
224 /// Returns a `Ready` representing HUP readiness.
225 ///
226 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
227 /// connection, or shut down the writing half of the connection.
228 ///
229 /// **Note that only readable and writable readiness is guaranteed to be
230 /// supported on all platforms**. This means that `hup` readiness
231 /// should be treated as a hint. For more details, see [readiness] in the
232 /// poll documentation. It is also unclear if HUP readiness will remain in 0.7. See
233 /// [here][issue-941].
234 ///
235 /// See [`Poll`] for more documentation on polling.
236 ///
237 /// # Examples
238 ///
239 /// ```
240 /// use corcovado::unix::UnixReady;
241 ///
242 /// let ready = UnixReady::hup();
243 ///
244 /// assert!(ready.is_hup());
245 /// ```
246 ///
247 /// [`Poll`]: ../struct.Poll.html
248 /// [readiness]: ../struct.Poll.html#readiness-operations
249 /// [issue-941]: https://github.com/tokio-rs/mio/issues/941
250 #[inline]
251 pub fn hup() -> UnixReady {
252 UnixReady(ready_from_usize(HUP))
253 }
254
255 /// Returns a `Ready` representing LIO completion readiness
256 ///
257 /// See [`Poll`] for more documentation on polling.
258 ///
259 /// # Examples
260 ///
261 /// ```
262 /// use corcovado::unix::UnixReady;
263 ///
264 /// let ready = UnixReady::lio();
265 ///
266 /// assert!(ready.is_lio());
267 /// ```
268 ///
269 /// [`Poll`]: struct.Poll.html
270 #[inline]
271 #[cfg(target_os = "freebsd")]
272 pub fn lio() -> UnixReady {
273 UnixReady(ready_from_usize(LIO))
274 }
275
276 /// Returns a `Ready` representing priority (`EPOLLPRI`) readiness
277 ///
278 /// See [`Poll`] for more documentation on polling.
279 ///
280 /// # Examples
281 ///
282 /// ```
283 /// use corcovado::unix::UnixReady;
284 ///
285 /// let ready = UnixReady::priority();
286 ///
287 /// assert!(ready.is_priority());
288 /// ```
289 ///
290 /// [`Poll`]: struct.Poll.html
291 #[inline]
292 #[cfg(any(
293 target_os = "android",
294 target_os = "illumos",
295 target_os = "linux",
296 target_os = "solaris"
297 ))]
298 pub fn priority() -> UnixReady {
299 UnixReady(ready_from_usize(PRI))
300 }
301
302 /// Returns true if `Ready` contains AIO readiness
303 ///
304 /// See [`Poll`] for more documentation on polling.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use corcovado::unix::UnixReady;
310 ///
311 /// let ready = UnixReady::aio();
312 ///
313 /// assert!(ready.is_aio());
314 /// ```
315 ///
316 /// [`Poll`]: ../struct.Poll.html
317 #[inline]
318 #[cfg(any(
319 target_os = "dragonfly",
320 target_os = "freebsd",
321 target_os = "ios",
322 target_os = "macos"
323 ))]
324 pub fn is_aio(&self) -> bool {
325 self.contains(ready_from_usize(AIO))
326 }
327
328 /// Returns true if the value includes error readiness
329 ///
330 /// **Note that only readable and writable readiness is guaranteed to be
331 /// supported on all platforms**. This means that `error` readiness should
332 /// be treated as a hint. For more details, see [readiness] in the poll
333 /// documentation.
334 ///
335 /// See [`Poll`] for more documentation on polling.
336 ///
337 /// # Examples
338 ///
339 /// ```
340 /// use corcovado::unix::UnixReady;
341 ///
342 /// let ready = UnixReady::error();
343 ///
344 /// assert!(ready.is_error());
345 /// ```
346 ///
347 /// [`Poll`]: ../struct.Poll.html
348 /// [readiness]: ../struct.Poll.html#readiness-operations
349 #[inline]
350 pub fn is_error(&self) -> bool {
351 self.contains(ready_from_usize(ERROR))
352 }
353
354 /// Returns true if the value includes HUP readiness
355 ///
356 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
357 /// connection, or shut down the writing half of the connection.
358 ///
359 /// **Note that only readable and writable readiness is guaranteed to be
360 /// supported on all platforms**. This means that `hup` readiness
361 /// should be treated as a hint. For more details, see [readiness] in the
362 /// poll documentation.
363 ///
364 /// See [`Poll`] for more documentation on polling.
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// use corcovado::unix::UnixReady;
370 ///
371 /// let ready = UnixReady::hup();
372 ///
373 /// assert!(ready.is_hup());
374 /// ```
375 ///
376 /// [`Poll`]: ../struct.Poll.html
377 /// [readiness]: ../struct.Poll.html#readiness-operations
378 #[inline]
379 pub fn is_hup(&self) -> bool {
380 self.contains(ready_from_usize(HUP))
381 }
382
383 /// Returns true if `Ready` contains LIO readiness
384 ///
385 /// See [`Poll`] for more documentation on polling.
386 ///
387 /// # Examples
388 ///
389 /// ```
390 /// use corcovado::unix::UnixReady;
391 ///
392 /// let ready = UnixReady::lio();
393 ///
394 /// assert!(ready.is_lio());
395 /// ```
396 #[inline]
397 #[cfg(target_os = "freebsd")]
398 pub fn is_lio(&self) -> bool {
399 self.contains(ready_from_usize(LIO))
400 }
401
402 /// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
403 ///
404 /// See [`Poll`] for more documentation on polling.
405 ///
406 /// # Examples
407 ///
408 /// ```
409 /// use corcovado::unix::UnixReady;
410 ///
411 /// let ready = UnixReady::priority();
412 ///
413 /// assert!(ready.is_priority());
414 /// ```
415 ///
416 /// [`Poll`]: struct.Poll.html
417 #[inline]
418 #[cfg(any(
419 target_os = "android",
420 target_os = "illumos",
421 target_os = "linux",
422 target_os = "solaris"
423 ))]
424 pub fn is_priority(&self) -> bool {
425 self.contains(ready_from_usize(PRI))
426 }
427}
428
429impl From<Ready> for UnixReady {
430 fn from(src: Ready) -> UnixReady {
431 UnixReady(src)
432 }
433}
434
435impl From<UnixReady> for Ready {
436 fn from(src: UnixReady) -> Ready {
437 src.0
438 }
439}
440
441impl ops::Deref for UnixReady {
442 type Target = Ready;
443
444 fn deref(&self) -> &Ready {
445 &self.0
446 }
447}
448
449impl ops::DerefMut for UnixReady {
450 fn deref_mut(&mut self) -> &mut Ready {
451 &mut self.0
452 }
453}
454
455impl ops::BitOr for UnixReady {
456 type Output = UnixReady;
457
458 #[inline]
459 fn bitor(self, other: UnixReady) -> UnixReady {
460 (self.0 | other.0).into()
461 }
462}
463
464impl ops::BitXor for UnixReady {
465 type Output = UnixReady;
466
467 #[inline]
468 fn bitxor(self, other: UnixReady) -> UnixReady {
469 (self.0 ^ other.0).into()
470 }
471}
472
473impl ops::BitAnd for UnixReady {
474 type Output = UnixReady;
475
476 #[inline]
477 fn bitand(self, other: UnixReady) -> UnixReady {
478 (self.0 & other.0).into()
479 }
480}
481
482impl ops::Sub for UnixReady {
483 type Output = UnixReady;
484
485 #[inline]
486 fn sub(self, other: UnixReady) -> UnixReady {
487 ready_from_usize(ready_as_usize(self.0) & !ready_as_usize(other.0)).into()
488 }
489}
490
491impl fmt::Debug for UnixReady {
492 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
493 let mut one = false;
494 let flags = [
495 (UnixReady(Ready::readable()), "Readable"),
496 (UnixReady(Ready::writable()), "Writable"),
497 (UnixReady::error(), "Error"),
498 (UnixReady::hup(), "Hup"),
499 #[allow(deprecated)]
500 (UnixReady::aio(), "Aio"),
501 #[cfg(any(
502 target_os = "android",
503 target_os = "illumos",
504 target_os = "linux",
505 target_os = "solaris"
506 ))]
507 (UnixReady::priority(), "Priority"),
508 ];
509
510 for &(flag, msg) in &flags {
511 if self.contains(flag) {
512 if one {
513 write!(fmt, " | ")?
514 }
515 write!(fmt, "{msg}")?;
516
517 one = true
518 }
519 }
520
521 if !one {
522 fmt.write_str("(empty)")?;
523 }
524
525 Ok(())
526 }
527}