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 /// ``` is_readable(self) -> bool86 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 /// ``` is_writable(self) -> bool103 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 /// ``` is_error(self) -> bool120 pub const fn is_error(self) -> bool { 121 self.0 & ERROR != 0 122 } 123 124 #[cfg(target_os = "freebsd")] is_aio(self) -> bool125 const fn is_aio(self) -> bool { 126 self.0 & AIO != 0 127 } 128 129 #[cfg(target_os = "freebsd")] is_lio(self) -> bool130 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"))))] is_priority(self) -> bool149 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"] add(self, other: Interest) -> Interest167 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"] remove(self, other: Interest) -> Option<Interest>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. to_mio(self) -> mio::Interest206 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 mask(self) -> Ready258 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] bitor(self, other: Self) -> Self274 fn bitor(self, other: Self) -> Self { 275 self.add(other) 276 } 277 } 278 279 impl ops::BitOrAssign for Interest { 280 #[inline] bitor_assign(&mut self, other: Self)281 fn bitor_assign(&mut self, other: Self) { 282 *self = *self | other; 283 } 284 } 285 286 impl fmt::Debug for Interest { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result287 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