retty_io/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 retty_io::Ready;
30/// use retty_io::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 retty_io::Ready;
42/// use retty_io::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<Error>> {
69/// use retty_io::{Ready, Poll, PollOpt, Token};
70/// use retty_io::net::TcpStream;
71/// use retty_io::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(any(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 retty_io::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 retty_io::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 retty_io::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/retty-io/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 retty_io::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(any(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 retty_io::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 retty_io::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 #[deprecated(since = "0.6.12", note = "this function is now platform specific")]
329 #[cfg(feature = "with-deprecated")]
330 #[cfg(not(any(
331 target_os = "dragonfly",
332 target_os = "freebsd",
333 target_os = "ios",
334 target_os = "macos"
335 )))]
336 #[doc(hidden)]
337 pub fn is_aio(&self) -> bool {
338 false
339 }
340
341 /// Returns true if the value includes error readiness
342 ///
343 /// **Note that only readable and writable readiness is guaranteed to be
344 /// supported on all platforms**. This means that `error` readiness should
345 /// be treated as a hint. For more details, see [readiness] in the poll
346 /// documentation.
347 ///
348 /// See [`Poll`] for more documentation on polling.
349 ///
350 /// # Examples
351 ///
352 /// ```
353 /// use retty_io::unix::UnixReady;
354 ///
355 /// let ready = UnixReady::error();
356 ///
357 /// assert!(ready.is_error());
358 /// ```
359 ///
360 /// [`Poll`]: ../struct.Poll.html
361 /// [readiness]: ../struct.Poll.html#readiness-operations
362 #[inline]
363 pub fn is_error(&self) -> bool {
364 self.contains(ready_from_usize(ERROR))
365 }
366
367 /// Returns true if the value includes HUP readiness
368 ///
369 /// A HUP (or hang-up) signifies that a stream socket **peer** closed the
370 /// connection, or shut down the writing half of the connection.
371 ///
372 /// **Note that only readable and writable readiness is guaranteed to be
373 /// supported on all platforms**. This means that `hup` readiness
374 /// should be treated as a hint. For more details, see [readiness] in the
375 /// poll documentation.
376 ///
377 /// See [`Poll`] for more documentation on polling.
378 ///
379 /// # Examples
380 ///
381 /// ```
382 /// use retty_io::unix::UnixReady;
383 ///
384 /// let ready = UnixReady::hup();
385 ///
386 /// assert!(ready.is_hup());
387 /// ```
388 ///
389 /// [`Poll`]: ../struct.Poll.html
390 /// [readiness]: ../struct.Poll.html#readiness-operations
391 #[inline]
392 pub fn is_hup(&self) -> bool {
393 self.contains(ready_from_usize(HUP))
394 }
395
396 /// Returns true if `Ready` contains LIO readiness
397 ///
398 /// See [`Poll`] for more documentation on polling.
399 ///
400 /// # Examples
401 ///
402 /// ```
403 /// use retty_io::unix::UnixReady;
404 ///
405 /// let ready = UnixReady::lio();
406 ///
407 /// assert!(ready.is_lio());
408 /// ```
409 #[inline]
410 #[cfg(any(target_os = "freebsd"))]
411 pub fn is_lio(&self) -> bool {
412 self.contains(ready_from_usize(LIO))
413 }
414
415 /// Returns true if `Ready` contains priority (`EPOLLPRI`) readiness
416 ///
417 /// See [`Poll`] for more documentation on polling.
418 ///
419 /// # Examples
420 ///
421 /// ```
422 /// use retty_io::unix::UnixReady;
423 ///
424 /// let ready = UnixReady::priority();
425 ///
426 /// assert!(ready.is_priority());
427 /// ```
428 ///
429 /// [`Poll`]: struct.Poll.html
430 #[inline]
431 #[cfg(any(
432 target_os = "android",
433 target_os = "illumos",
434 target_os = "linux",
435 target_os = "solaris"
436 ))]
437 pub fn is_priority(&self) -> bool {
438 self.contains(ready_from_usize(PRI))
439 }
440}
441
442impl From<Ready> for UnixReady {
443 fn from(src: Ready) -> UnixReady {
444 UnixReady(src)
445 }
446}
447
448impl From<UnixReady> for Ready {
449 fn from(src: UnixReady) -> Ready {
450 src.0
451 }
452}
453
454impl ops::Deref for UnixReady {
455 type Target = Ready;
456
457 fn deref(&self) -> &Ready {
458 &self.0
459 }
460}
461
462impl ops::DerefMut for UnixReady {
463 fn deref_mut(&mut self) -> &mut Ready {
464 &mut self.0
465 }
466}
467
468impl ops::BitOr for UnixReady {
469 type Output = UnixReady;
470
471 #[inline]
472 fn bitor(self, other: UnixReady) -> UnixReady {
473 (self.0 | other.0).into()
474 }
475}
476
477impl ops::BitXor for UnixReady {
478 type Output = UnixReady;
479
480 #[inline]
481 fn bitxor(self, other: UnixReady) -> UnixReady {
482 (self.0 ^ other.0).into()
483 }
484}
485
486impl ops::BitAnd for UnixReady {
487 type Output = UnixReady;
488
489 #[inline]
490 fn bitand(self, other: UnixReady) -> UnixReady {
491 (self.0 & other.0).into()
492 }
493}
494
495impl ops::Sub for UnixReady {
496 type Output = UnixReady;
497
498 #[inline]
499 fn sub(self, other: UnixReady) -> UnixReady {
500 ready_from_usize(ready_as_usize(self.0) & !ready_as_usize(other.0)).into()
501 }
502}
503
504#[cfg(feature = "with-deprecated")]
505#[doc(hidden)]
506impl ops::Not for UnixReady {
507 type Output = UnixReady;
508
509 #[inline]
510 fn not(self) -> UnixReady {
511 (!self.0).into()
512 }
513}
514
515impl fmt::Debug for UnixReady {
516 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
517 let mut one = false;
518 let flags = [
519 (UnixReady(Ready::readable()), "Readable"),
520 (UnixReady(Ready::writable()), "Writable"),
521 (UnixReady::error(), "Error"),
522 (UnixReady::hup(), "Hup"),
523 #[allow(deprecated)]
524 (UnixReady::aio(), "Aio"),
525 #[cfg(any(
526 target_os = "android",
527 target_os = "illumos",
528 target_os = "linux",
529 target_os = "solaris"
530 ))]
531 (UnixReady::priority(), "Priority"),
532 ];
533
534 for &(flag, msg) in &flags {
535 if self.contains(flag) {
536 if one {
537 write!(fmt, " | ")?
538 }
539 write!(fmt, "{}", msg)?;
540
541 one = true
542 }
543 }
544
545 if !one {
546 fmt.write_str("(empty)")?;
547 }
548
549 Ok(())
550 }
551}