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()); add(self, other: Interest) -> Interest166 pub const fn add(self, other: Interest) -> Interest { 167 Self(self.0 | other.0) 168 } 169 170 // This function must be crate-private to avoid exposing a `mio` dependency. to_mio(self) -> mio::Interest171 pub(crate) fn to_mio(self) -> mio::Interest { 172 fn mio_add(wrapped: &mut Option<mio::Interest>, add: mio::Interest) { 173 match wrapped { 174 Some(inner) => *inner |= add, 175 None => *wrapped = Some(add), 176 } 177 } 178 179 // mio does not allow and empty interest, so use None for empty 180 let mut mio = None; 181 182 if self.is_readable() { 183 mio_add(&mut mio, mio::Interest::READABLE); 184 } 185 186 if self.is_writable() { 187 mio_add(&mut mio, mio::Interest::WRITABLE); 188 } 189 190 #[cfg(any(target_os = "linux", target_os = "android"))] 191 if self.is_priority() { 192 mio_add(&mut mio, mio::Interest::PRIORITY); 193 } 194 195 #[cfg(target_os = "freebsd")] 196 if self.is_aio() { 197 mio_add(&mut mio, mio::Interest::AIO); 198 } 199 200 #[cfg(target_os = "freebsd")] 201 if self.is_lio() { 202 mio_add(&mut mio, mio::Interest::LIO); 203 } 204 205 if self.is_error() { 206 // There is no error interest in mio, because error events are always reported. 207 // But mio interests cannot be empty and an interest is needed just for the registeration. 208 // 209 // read readiness is filtered out in `Interest::mask` or `Ready::from_interest` if 210 // the read interest was not specified by the user. 211 mio_add(&mut mio, mio::Interest::READABLE); 212 } 213 214 // the default `mio::Interest::READABLE` should never be used in practice. Either 215 // 216 // - at least one tokio interest with a mio counterpart was used 217 // - only the error tokio interest was specified 218 // 219 // in both cases, `mio` is Some already 220 mio.unwrap_or(mio::Interest::READABLE) 221 } 222 mask(self) -> Ready223 pub(crate) fn mask(self) -> Ready { 224 match self { 225 Interest::READABLE => Ready::READABLE | Ready::READ_CLOSED, 226 Interest::WRITABLE => Ready::WRITABLE | Ready::WRITE_CLOSED, 227 #[cfg(any(target_os = "linux", target_os = "android"))] 228 Interest::PRIORITY => Ready::PRIORITY | Ready::READ_CLOSED, 229 Interest::ERROR => Ready::ERROR, 230 _ => Ready::EMPTY, 231 } 232 } 233 } 234 235 impl ops::BitOr for Interest { 236 type Output = Self; 237 238 #[inline] bitor(self, other: Self) -> Self239 fn bitor(self, other: Self) -> Self { 240 self.add(other) 241 } 242 } 243 244 impl ops::BitOrAssign for Interest { 245 #[inline] bitor_assign(&mut self, other: Self)246 fn bitor_assign(&mut self, other: Self) { 247 *self = *self | other 248 } 249 } 250 251 impl fmt::Debug for Interest { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result252 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 253 let mut separator = false; 254 255 if self.is_readable() { 256 if separator { 257 write!(fmt, " | ")?; 258 } 259 write!(fmt, "READABLE")?; 260 separator = true; 261 } 262 263 if self.is_writable() { 264 if separator { 265 write!(fmt, " | ")?; 266 } 267 write!(fmt, "WRITABLE")?; 268 separator = true; 269 } 270 271 #[cfg(any(target_os = "linux", target_os = "android"))] 272 if self.is_priority() { 273 if separator { 274 write!(fmt, " | ")?; 275 } 276 write!(fmt, "PRIORITY")?; 277 separator = true; 278 } 279 280 #[cfg(target_os = "freebsd")] 281 if self.is_aio() { 282 if separator { 283 write!(fmt, " | ")?; 284 } 285 write!(fmt, "AIO")?; 286 separator = true; 287 } 288 289 #[cfg(target_os = "freebsd")] 290 if self.is_lio() { 291 if separator { 292 write!(fmt, " | ")?; 293 } 294 write!(fmt, "LIO")?; 295 separator = true; 296 } 297 298 if self.is_error() { 299 if separator { 300 write!(fmt, " | ")?; 301 } 302 write!(fmt, "ERROR")?; 303 separator = true; 304 } 305 306 let _ = separator; 307 308 Ok(()) 309 } 310 } 311