Source code
Revision control
Copy as Markdown
Other Tools
#![cfg_attr(not(feature = "net"), allow(dead_code, unreachable_pub))]
use crate::io::ready::Ready;
use std::fmt;
use std::ops;
// These must be unique.
// same as mio
const READABLE: usize = 0b0001;
const WRITABLE: usize = 0b0010;
// The following are not available on all platforms.
#[cfg(target_os = "freebsd")]
const AIO: usize = 0b0100;
#[cfg(target_os = "freebsd")]
const LIO: usize = 0b1000;
#[cfg(any(target_os = "linux", target_os = "android"))]
const PRIORITY: usize = 0b0001_0000;
// error is available on all platforms, but behavior is platform-specific
// mio does not have this interest
const ERROR: usize = 0b0010_0000;
/// Readiness event interest.
///
/// Specifies the readiness events the caller is interested in when awaiting on
/// I/O resource readiness states.
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct Interest(usize);
impl Interest {
// The non-FreeBSD definitions in this block are active only when
// building documentation.
cfg_aio! {
/// Interest for POSIX AIO.
#[cfg(target_os = "freebsd")]
pub const AIO: Interest = Interest(AIO);
/// Interest for POSIX AIO.
#[cfg(not(target_os = "freebsd"))]
pub const AIO: Interest = Interest(READABLE);
/// Interest for POSIX AIO `lio_listio` events.
#[cfg(target_os = "freebsd")]
pub const LIO: Interest = Interest(LIO);
/// Interest for POSIX AIO `lio_listio` events.
#[cfg(not(target_os = "freebsd"))]
pub const LIO: Interest = Interest(READABLE);
}
/// Interest in all readable events.
///
/// Readable interest includes read-closed events.
pub const READABLE: Interest = Interest(READABLE);
/// Interest in all writable events.
///
/// Writable interest includes write-closed events.
pub const WRITABLE: Interest = Interest(WRITABLE);
/// Interest in error events.
///
/// Passes error interest to the underlying OS selector.
/// Behavior is platform-specific, read your platform's documentation.
pub const ERROR: Interest = Interest(ERROR);
/// Returns a `Interest` set representing priority completion interests.
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
pub const PRIORITY: Interest = Interest(PRIORITY);
/// Returns true if the value includes readable interest.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// assert!(Interest::READABLE.is_readable());
/// assert!(!Interest::WRITABLE.is_readable());
///
/// let both = Interest::READABLE | Interest::WRITABLE;
/// assert!(both.is_readable());
/// ```
pub const fn is_readable(self) -> bool {
self.0 & READABLE != 0
}
/// Returns true if the value includes writable interest.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// assert!(!Interest::READABLE.is_writable());
/// assert!(Interest::WRITABLE.is_writable());
///
/// let both = Interest::READABLE | Interest::WRITABLE;
/// assert!(both.is_writable());
/// ```
pub const fn is_writable(self) -> bool {
self.0 & WRITABLE != 0
}
/// Returns true if the value includes error interest.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// assert!(Interest::ERROR.is_error());
/// assert!(!Interest::WRITABLE.is_error());
///
/// let combined = Interest::READABLE | Interest::ERROR;
/// assert!(combined.is_error());
/// ```
pub const fn is_error(self) -> bool {
self.0 & ERROR != 0
}
#[cfg(target_os = "freebsd")]
const fn is_aio(self) -> bool {
self.0 & AIO != 0
}
#[cfg(target_os = "freebsd")]
const fn is_lio(self) -> bool {
self.0 & LIO != 0
}
/// Returns true if the value includes priority interest.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// assert!(!Interest::READABLE.is_priority());
/// assert!(Interest::PRIORITY.is_priority());
///
/// let both = Interest::READABLE | Interest::PRIORITY;
/// assert!(both.is_priority());
/// ```
#[cfg(any(target_os = "linux", target_os = "android"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))]
pub const fn is_priority(self) -> bool {
self.0 & PRIORITY != 0
}
/// Add together two `Interest` values.
///
/// This function works from a `const` context.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// const BOTH: Interest = Interest::READABLE.add(Interest::WRITABLE);
///
/// assert!(BOTH.is_readable());
/// assert!(BOTH.is_writable());
#[must_use = "this returns the result of the operation, without modifying the original"]
pub const fn add(self, other: Interest) -> Interest {
Self(self.0 | other.0)
}
/// Remove `Interest` from `self`.
///
/// Interests present in `other` but *not* in `self` are ignored.
///
/// Returns `None` if the set would be empty after removing `Interest`.
///
/// # Examples
///
/// ```
/// use tokio::io::Interest;
///
/// const RW_INTEREST: Interest = Interest::READABLE.add(Interest::WRITABLE);
///
/// let w_interest = RW_INTEREST.remove(Interest::READABLE).unwrap();
/// assert!(!w_interest.is_readable());
/// assert!(w_interest.is_writable());
///
/// // Removing all interests from the set returns `None`.
/// assert_eq!(w_interest.remove(Interest::WRITABLE), None);
///
/// // Remove all interests at once.
/// assert_eq!(RW_INTEREST.remove(RW_INTEREST), None);
/// ```
#[must_use = "this returns the result of the operation, without modifying the original"]
pub fn remove(self, other: Interest) -> Option<Interest> {
let value = self.0 & !other.0;
if value != 0 {
Some(Self(value))
} else {
None
}
}
// This function must be crate-private to avoid exposing a `mio` dependency.
pub(crate) fn to_mio(self) -> mio::Interest {
fn mio_add(wrapped: &mut Option<mio::Interest>, add: mio::Interest) {
match wrapped {
Some(inner) => *inner |= add,
None => *wrapped = Some(add),
}
}
// mio does not allow and empty interest, so use None for empty
let mut mio = None;
if self.is_readable() {
mio_add(&mut mio, mio::Interest::READABLE);
}
if self.is_writable() {
mio_add(&mut mio, mio::Interest::WRITABLE);
}
#[cfg(any(target_os = "linux", target_os = "android"))]
if self.is_priority() {
mio_add(&mut mio, mio::Interest::PRIORITY);
}
#[cfg(target_os = "freebsd")]
if self.is_aio() {
mio_add(&mut mio, mio::Interest::AIO);
}
#[cfg(target_os = "freebsd")]
if self.is_lio() {
mio_add(&mut mio, mio::Interest::LIO);
}
if self.is_error() {
// There is no error interest in mio, because error events are always reported.
// But mio interests cannot be empty and an interest is needed just for the registration.
//
// read readiness is filtered out in `Interest::mask` or `Ready::from_interest` if
// the read interest was not specified by the user.
mio_add(&mut mio, mio::Interest::READABLE);
}
// the default `mio::Interest::READABLE` should never be used in practice. Either
//
// - at least one tokio interest with a mio counterpart was used
// - only the error tokio interest was specified
//
// in both cases, `mio` is Some already
mio.unwrap_or(mio::Interest::READABLE)
}
pub(crate) fn mask(self) -> Ready {
match self {
Interest::READABLE => Ready::READABLE | Ready::READ_CLOSED,
Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED,
#[cfg(any(target_os = "linux", target_os = "android"))]
Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED,
Interest::ERROR => Ready::ERROR,
_ => Ready::EMPTY,
}
}
}
impl ops::BitOr for Interest {
type Output = Self;
#[inline]
fn bitor(self, other: Self) -> Self {
self.add(other)
}
}
impl ops::BitOrAssign for Interest {
#[inline]
fn bitor_assign(&mut self, other: Self) {
*self = *self | other;
}
}
impl fmt::Debug for Interest {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut separator = false;
if self.is_readable() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "READABLE")?;
separator = true;
}
if self.is_writable() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "WRITABLE")?;
separator = true;
}
#[cfg(any(target_os = "linux", target_os = "android"))]
if self.is_priority() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "PRIORITY")?;
separator = true;
}
#[cfg(target_os = "freebsd")]
if self.is_aio() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "AIO")?;
separator = true;
}
#[cfg(target_os = "freebsd")]
if self.is_lio() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "LIO")?;
separator = true;
}
if self.is_error() {
if separator {
write!(fmt, " | ")?;
}
write!(fmt, "ERROR")?;
separator = true;
}
let _ = separator;
Ok(())
}
}