| 1 | #![cfg_attr (not(feature = "net" ), allow(dead_code, unreachable_pub))] |
| 2 | |
| 3 | use crate::io::ready::Ready; |
| 4 | |
| 5 | use std::fmt; |
| 6 | use std::ops; |
| 7 | |
| 8 | // These must be unique. |
| 9 | // same as mio |
| 10 | const READABLE: usize = 0b0001; |
| 11 | const WRITABLE: usize = 0b0010; |
| 12 | // The following are not available on all platforms. |
| 13 | #[cfg (target_os = "freebsd" )] |
| 14 | const AIO: usize = 0b0100; |
| 15 | #[cfg (target_os = "freebsd" )] |
| 16 | const LIO: usize = 0b1000; |
| 17 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 18 | const PRIORITY: usize = 0b0001_0000; |
| 19 | // error is available on all platforms, but behavior is platform-specific |
| 20 | // mio does not have this interest |
| 21 | const ERROR: usize = 0b0010_0000; |
| 22 | |
| 23 | /// Readiness event interest. |
| 24 | /// |
| 25 | /// Specifies the readiness events the caller is interested in when awaiting on |
| 26 | /// I/O resource readiness states. |
| 27 | #[cfg_attr (docsrs, doc(cfg(feature = "net" )))] |
| 28 | #[derive (Clone, Copy, Eq, PartialEq)] |
| 29 | pub struct Interest(usize); |
| 30 | |
| 31 | impl Interest { |
| 32 | // The non-FreeBSD definitions in this block are active only when |
| 33 | // building documentation. |
| 34 | cfg_aio! { |
| 35 | /// Interest for POSIX AIO. |
| 36 | #[cfg (target_os = "freebsd" )] |
| 37 | pub const AIO: Interest = Interest(AIO); |
| 38 | |
| 39 | /// Interest for POSIX AIO. |
| 40 | #[cfg (not(target_os = "freebsd" ))] |
| 41 | pub const AIO: Interest = Interest(READABLE); |
| 42 | |
| 43 | /// Interest for POSIX AIO `lio_listio` events. |
| 44 | #[cfg (target_os = "freebsd" )] |
| 45 | pub const LIO: Interest = Interest(LIO); |
| 46 | |
| 47 | /// Interest for POSIX AIO `lio_listio` events. |
| 48 | #[cfg (not(target_os = "freebsd" ))] |
| 49 | pub const LIO: Interest = Interest(READABLE); |
| 50 | } |
| 51 | |
| 52 | /// Interest in all readable events. |
| 53 | /// |
| 54 | /// Readable interest includes read-closed events. |
| 55 | pub const READABLE: Interest = Interest(READABLE); |
| 56 | |
| 57 | /// Interest in all writable events. |
| 58 | /// |
| 59 | /// Writable interest includes write-closed events. |
| 60 | pub const WRITABLE: Interest = Interest(WRITABLE); |
| 61 | |
| 62 | /// Interest in error events. |
| 63 | /// |
| 64 | /// Passes error interest to the underlying OS selector. |
| 65 | /// Behavior is platform-specific, read your platform's documentation. |
| 66 | pub const ERROR: Interest = Interest(ERROR); |
| 67 | |
| 68 | /// Returns a `Interest` set representing priority completion interests. |
| 69 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 70 | #[cfg_attr (docsrs, doc(cfg(any(target_os = "linux" , target_os = "android" ))))] |
| 71 | pub const PRIORITY: Interest = Interest(PRIORITY); |
| 72 | |
| 73 | /// Returns true if the value includes readable interest. |
| 74 | /// |
| 75 | /// # Examples |
| 76 | /// |
| 77 | /// ``` |
| 78 | /// use tokio::io::Interest; |
| 79 | /// |
| 80 | /// assert!(Interest::READABLE.is_readable()); |
| 81 | /// assert!(!Interest::WRITABLE.is_readable()); |
| 82 | /// |
| 83 | /// let both = Interest::READABLE | Interest::WRITABLE; |
| 84 | /// assert!(both.is_readable()); |
| 85 | /// ``` |
| 86 | pub const fn is_readable(self) -> bool { |
| 87 | self.0 & READABLE != 0 |
| 88 | } |
| 89 | |
| 90 | /// Returns true if the value includes writable interest. |
| 91 | /// |
| 92 | /// # Examples |
| 93 | /// |
| 94 | /// ``` |
| 95 | /// use tokio::io::Interest; |
| 96 | /// |
| 97 | /// assert!(!Interest::READABLE.is_writable()); |
| 98 | /// assert!(Interest::WRITABLE.is_writable()); |
| 99 | /// |
| 100 | /// let both = Interest::READABLE | Interest::WRITABLE; |
| 101 | /// assert!(both.is_writable()); |
| 102 | /// ``` |
| 103 | pub const fn is_writable(self) -> bool { |
| 104 | self.0 & WRITABLE != 0 |
| 105 | } |
| 106 | |
| 107 | /// Returns true if the value includes error interest. |
| 108 | /// |
| 109 | /// # Examples |
| 110 | /// |
| 111 | /// ``` |
| 112 | /// use tokio::io::Interest; |
| 113 | /// |
| 114 | /// assert!(Interest::ERROR.is_error()); |
| 115 | /// assert!(!Interest::WRITABLE.is_error()); |
| 116 | /// |
| 117 | /// let combined = Interest::READABLE | Interest::ERROR; |
| 118 | /// assert!(combined.is_error()); |
| 119 | /// ``` |
| 120 | pub const fn is_error(self) -> bool { |
| 121 | self.0 & ERROR != 0 |
| 122 | } |
| 123 | |
| 124 | #[cfg (target_os = "freebsd" )] |
| 125 | const fn is_aio(self) -> bool { |
| 126 | self.0 & AIO != 0 |
| 127 | } |
| 128 | |
| 129 | #[cfg (target_os = "freebsd" )] |
| 130 | const fn is_lio(self) -> bool { |
| 131 | self.0 & LIO != 0 |
| 132 | } |
| 133 | |
| 134 | /// Returns true if the value includes priority interest. |
| 135 | /// |
| 136 | /// # Examples |
| 137 | /// |
| 138 | /// ``` |
| 139 | /// use tokio::io::Interest; |
| 140 | /// |
| 141 | /// assert!(!Interest::READABLE.is_priority()); |
| 142 | /// assert!(Interest::PRIORITY.is_priority()); |
| 143 | /// |
| 144 | /// let both = Interest::READABLE | Interest::PRIORITY; |
| 145 | /// assert!(both.is_priority()); |
| 146 | /// ``` |
| 147 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 148 | #[cfg_attr (docsrs, doc(cfg(any(target_os = "linux" , target_os = "android" ))))] |
| 149 | pub const fn is_priority(self) -> bool { |
| 150 | self.0 & PRIORITY != 0 |
| 151 | } |
| 152 | |
| 153 | /// Add together two `Interest` values. |
| 154 | /// |
| 155 | /// This function works from a `const` context. |
| 156 | /// |
| 157 | /// # Examples |
| 158 | /// |
| 159 | /// ``` |
| 160 | /// use tokio::io::Interest; |
| 161 | /// |
| 162 | /// const BOTH: Interest = Interest::READABLE.add(Interest::WRITABLE); |
| 163 | /// |
| 164 | /// assert!(BOTH.is_readable()); |
| 165 | /// assert!(BOTH.is_writable()); |
| 166 | #[must_use = "this returns the result of the operation, without modifying the original" ] |
| 167 | pub const fn add(self, other: Interest) -> Interest { |
| 168 | Self(self.0 | other.0) |
| 169 | } |
| 170 | |
| 171 | /// Remove `Interest` from `self`. |
| 172 | /// |
| 173 | /// Interests present in `other` but *not* in `self` are ignored. |
| 174 | /// |
| 175 | /// Returns `None` if the set would be empty after removing `Interest`. |
| 176 | /// |
| 177 | /// # Examples |
| 178 | /// |
| 179 | /// ``` |
| 180 | /// use tokio::io::Interest; |
| 181 | /// |
| 182 | /// const RW_INTEREST: Interest = Interest::READABLE.add(Interest::WRITABLE); |
| 183 | /// |
| 184 | /// let w_interest = RW_INTEREST.remove(Interest::READABLE).unwrap(); |
| 185 | /// assert!(!w_interest.is_readable()); |
| 186 | /// assert!(w_interest.is_writable()); |
| 187 | /// |
| 188 | /// // Removing all interests from the set returns `None`. |
| 189 | /// assert_eq!(w_interest.remove(Interest::WRITABLE), None); |
| 190 | /// |
| 191 | /// // Remove all interests at once. |
| 192 | /// assert_eq!(RW_INTEREST.remove(RW_INTEREST), None); |
| 193 | /// ``` |
| 194 | #[must_use = "this returns the result of the operation, without modifying the original" ] |
| 195 | pub fn remove(self, other: Interest) -> Option<Interest> { |
| 196 | let value = self.0 & !other.0; |
| 197 | |
| 198 | if value != 0 { |
| 199 | Some(Self(value)) |
| 200 | } else { |
| 201 | None |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | // This function must be crate-private to avoid exposing a `mio` dependency. |
| 206 | pub(crate) fn to_mio(self) -> mio::Interest { |
| 207 | fn mio_add(wrapped: &mut Option<mio::Interest>, add: mio::Interest) { |
| 208 | match wrapped { |
| 209 | Some(inner) => *inner |= add, |
| 210 | None => *wrapped = Some(add), |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | // mio does not allow and empty interest, so use None for empty |
| 215 | let mut mio = None; |
| 216 | |
| 217 | if self.is_readable() { |
| 218 | mio_add(&mut mio, mio::Interest::READABLE); |
| 219 | } |
| 220 | |
| 221 | if self.is_writable() { |
| 222 | mio_add(&mut mio, mio::Interest::WRITABLE); |
| 223 | } |
| 224 | |
| 225 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 226 | if self.is_priority() { |
| 227 | mio_add(&mut mio, mio::Interest::PRIORITY); |
| 228 | } |
| 229 | |
| 230 | #[cfg (target_os = "freebsd" )] |
| 231 | if self.is_aio() { |
| 232 | mio_add(&mut mio, mio::Interest::AIO); |
| 233 | } |
| 234 | |
| 235 | #[cfg (target_os = "freebsd" )] |
| 236 | if self.is_lio() { |
| 237 | mio_add(&mut mio, mio::Interest::LIO); |
| 238 | } |
| 239 | |
| 240 | if self.is_error() { |
| 241 | // There is no error interest in mio, because error events are always reported. |
| 242 | // But mio interests cannot be empty and an interest is needed just for the registration. |
| 243 | // |
| 244 | // read readiness is filtered out in `Interest::mask` or `Ready::from_interest` if |
| 245 | // the read interest was not specified by the user. |
| 246 | mio_add(&mut mio, mio::Interest::READABLE); |
| 247 | } |
| 248 | |
| 249 | // the default `mio::Interest::READABLE` should never be used in practice. Either |
| 250 | // |
| 251 | // - at least one tokio interest with a mio counterpart was used |
| 252 | // - only the error tokio interest was specified |
| 253 | // |
| 254 | // in both cases, `mio` is Some already |
| 255 | mio.unwrap_or(mio::Interest::READABLE) |
| 256 | } |
| 257 | |
| 258 | pub(crate) fn mask(self) -> Ready { |
| 259 | match self { |
| 260 | Interest::READABLE => Ready::READABLE | Ready::READ_CLOSED, |
| 261 | Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED, |
| 262 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 263 | Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED, |
| 264 | Interest::ERROR => Ready::ERROR, |
| 265 | _ => Ready::EMPTY, |
| 266 | } |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | impl ops::BitOr for Interest { |
| 271 | type Output = Self; |
| 272 | |
| 273 | #[inline ] |
| 274 | fn bitor(self, other: Self) -> Self { |
| 275 | self.add(other) |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | impl ops::BitOrAssign for Interest { |
| 280 | #[inline ] |
| 281 | fn bitor_assign(&mut self, other: Self) { |
| 282 | *self = *self | other; |
| 283 | } |
| 284 | } |
| 285 | |
| 286 | impl fmt::Debug for Interest { |
| 287 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 288 | let mut separator = false; |
| 289 | |
| 290 | if self.is_readable() { |
| 291 | if separator { |
| 292 | write!(fmt, " | " )?; |
| 293 | } |
| 294 | write!(fmt, "READABLE" )?; |
| 295 | separator = true; |
| 296 | } |
| 297 | |
| 298 | if self.is_writable() { |
| 299 | if separator { |
| 300 | write!(fmt, " | " )?; |
| 301 | } |
| 302 | write!(fmt, "WRITABLE" )?; |
| 303 | separator = true; |
| 304 | } |
| 305 | |
| 306 | #[cfg (any(target_os = "linux" , target_os = "android" ))] |
| 307 | if self.is_priority() { |
| 308 | if separator { |
| 309 | write!(fmt, " | " )?; |
| 310 | } |
| 311 | write!(fmt, "PRIORITY" )?; |
| 312 | separator = true; |
| 313 | } |
| 314 | |
| 315 | #[cfg (target_os = "freebsd" )] |
| 316 | if self.is_aio() { |
| 317 | if separator { |
| 318 | write!(fmt, " | " )?; |
| 319 | } |
| 320 | write!(fmt, "AIO" )?; |
| 321 | separator = true; |
| 322 | } |
| 323 | |
| 324 | #[cfg (target_os = "freebsd" )] |
| 325 | if self.is_lio() { |
| 326 | if separator { |
| 327 | write!(fmt, " | " )?; |
| 328 | } |
| 329 | write!(fmt, "LIO" )?; |
| 330 | separator = true; |
| 331 | } |
| 332 | |
| 333 | if self.is_error() { |
| 334 | if separator { |
| 335 | write!(fmt, " | " )?; |
| 336 | } |
| 337 | write!(fmt, "ERROR" )?; |
| 338 | separator = true; |
| 339 | } |
| 340 | |
| 341 | let _ = separator; |
| 342 | |
| 343 | Ok(()) |
| 344 | } |
| 345 | } |
| 346 | |