1 #![cfg_attr(not(feature = "net"), allow(unreachable_pub))] 2 3 use crate::io::interest::Interest; 4 5 use std::fmt; 6 use std::ops; 7 8 const READABLE: usize = 0b0_01; 9 const WRITABLE: usize = 0b0_10; 10 const READ_CLOSED: usize = 0b0_0100; 11 const WRITE_CLOSED: usize = 0b0_1000; 12 #[cfg(any(target_os = "linux", target_os = "android"))] 13 const PRIORITY: usize = 0b1_0000; 14 const ERROR: usize = 0b10_0000; 15 16 /// Describes the readiness state of an I/O resources. 17 /// 18 /// `Ready` tracks which operation an I/O resource is ready to perform. 19 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 20 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 21 pub struct Ready(usize); 22 23 impl Ready { 24 /// Returns the empty `Ready` set. 25 pub const EMPTY: Ready = Ready(0); 26 27 /// Returns a `Ready` representing readable readiness. 28 pub const READABLE: Ready = Ready(READABLE); 29 30 /// Returns a `Ready` representing writable readiness. 31 pub const WRITABLE: Ready = Ready(WRITABLE); 32 33 /// Returns a `Ready` representing read closed readiness. 34 pub const READ_CLOSED: Ready = Ready(READ_CLOSED); 35 36 /// Returns a `Ready` representing write closed readiness. 37 pub const WRITE_CLOSED: Ready = Ready(WRITE_CLOSED); 38 39 /// Returns a `Ready` representing priority readiness. 40 #[cfg(any(target_os = "linux", target_os = "android"))] 41 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))] 42 pub const PRIORITY: Ready = Ready(PRIORITY); 43 44 /// Returns a `Ready` representing error readiness. 45 pub const ERROR: Ready = Ready(ERROR); 46 47 /// Returns a `Ready` representing readiness for all operations. 48 #[cfg(any(target_os = "linux", target_os = "android"))] 49 pub const ALL: Ready = 50 Ready(READABLE | WRITABLE | READ_CLOSED | WRITE_CLOSED | ERROR | PRIORITY); 51 52 /// Returns a `Ready` representing readiness for all operations. 53 #[cfg(not(any(target_os = "linux", target_os = "android")))] 54 pub const ALL: Ready = Ready(READABLE | WRITABLE | READ_CLOSED | WRITE_CLOSED | ERROR); 55 56 // Must remain crate-private to avoid adding a public dependency on Mio. from_mio(event: &mio::event::Event) -> Ready57 pub(crate) fn from_mio(event: &mio::event::Event) -> Ready { 58 let mut ready = Ready::EMPTY; 59 60 #[cfg(all(target_os = "freebsd", feature = "net"))] 61 { 62 if event.is_aio() { 63 ready |= Ready::READABLE; 64 } 65 66 if event.is_lio() { 67 ready |= Ready::READABLE; 68 } 69 } 70 71 if event.is_readable() { 72 ready |= Ready::READABLE; 73 } 74 75 if event.is_writable() { 76 ready |= Ready::WRITABLE; 77 } 78 79 if event.is_read_closed() { 80 ready |= Ready::READ_CLOSED; 81 } 82 83 if event.is_write_closed() { 84 ready |= Ready::WRITE_CLOSED; 85 } 86 87 if event.is_error() { 88 ready |= Ready::ERROR; 89 } 90 91 #[cfg(any(target_os = "linux", target_os = "android"))] 92 { 93 if event.is_priority() { 94 ready |= Ready::PRIORITY; 95 } 96 } 97 98 ready 99 } 100 101 /// Returns true if `Ready` is the empty set. 102 /// 103 /// # Examples 104 /// 105 /// ``` 106 /// use tokio::io::Ready; 107 /// 108 /// assert!(Ready::EMPTY.is_empty()); 109 /// assert!(!Ready::READABLE.is_empty()); 110 /// ``` is_empty(self) -> bool111 pub fn is_empty(self) -> bool { 112 self == Ready::EMPTY 113 } 114 115 /// Returns `true` if the value includes `readable`. 116 /// 117 /// # Examples 118 /// 119 /// ``` 120 /// use tokio::io::Ready; 121 /// 122 /// assert!(!Ready::EMPTY.is_readable()); 123 /// assert!(Ready::READABLE.is_readable()); 124 /// assert!(Ready::READ_CLOSED.is_readable()); 125 /// assert!(!Ready::WRITABLE.is_readable()); 126 /// ``` is_readable(self) -> bool127 pub fn is_readable(self) -> bool { 128 self.contains(Ready::READABLE) || self.is_read_closed() 129 } 130 131 /// Returns `true` if the value includes writable `readiness`. 132 /// 133 /// # Examples 134 /// 135 /// ``` 136 /// use tokio::io::Ready; 137 /// 138 /// assert!(!Ready::EMPTY.is_writable()); 139 /// assert!(!Ready::READABLE.is_writable()); 140 /// assert!(Ready::WRITABLE.is_writable()); 141 /// assert!(Ready::WRITE_CLOSED.is_writable()); 142 /// ``` is_writable(self) -> bool143 pub fn is_writable(self) -> bool { 144 self.contains(Ready::WRITABLE) || self.is_write_closed() 145 } 146 147 /// Returns `true` if the value includes read-closed `readiness`. 148 /// 149 /// # Examples 150 /// 151 /// ``` 152 /// use tokio::io::Ready; 153 /// 154 /// assert!(!Ready::EMPTY.is_read_closed()); 155 /// assert!(!Ready::READABLE.is_read_closed()); 156 /// assert!(Ready::READ_CLOSED.is_read_closed()); 157 /// ``` is_read_closed(self) -> bool158 pub fn is_read_closed(self) -> bool { 159 self.contains(Ready::READ_CLOSED) 160 } 161 162 /// Returns `true` if the value includes write-closed `readiness`. 163 /// 164 /// # Examples 165 /// 166 /// ``` 167 /// use tokio::io::Ready; 168 /// 169 /// assert!(!Ready::EMPTY.is_write_closed()); 170 /// assert!(!Ready::WRITABLE.is_write_closed()); 171 /// assert!(Ready::WRITE_CLOSED.is_write_closed()); 172 /// ``` is_write_closed(self) -> bool173 pub fn is_write_closed(self) -> bool { 174 self.contains(Ready::WRITE_CLOSED) 175 } 176 177 /// Returns `true` if the value includes priority `readiness`. 178 /// 179 /// # Examples 180 /// 181 /// ``` 182 /// use tokio::io::Ready; 183 /// 184 /// assert!(!Ready::EMPTY.is_priority()); 185 /// assert!(!Ready::WRITABLE.is_priority()); 186 /// assert!(Ready::PRIORITY.is_priority()); 187 /// ``` 188 #[cfg(any(target_os = "linux", target_os = "android"))] 189 #[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "android"))))] is_priority(self) -> bool190 pub fn is_priority(self) -> bool { 191 self.contains(Ready::PRIORITY) 192 } 193 194 /// Returns `true` if the value includes error `readiness`. 195 /// 196 /// # Examples 197 /// 198 /// ``` 199 /// use tokio::io::Ready; 200 /// 201 /// assert!(!Ready::EMPTY.is_error()); 202 /// assert!(!Ready::WRITABLE.is_error()); 203 /// assert!(Ready::ERROR.is_error()); 204 /// ``` is_error(self) -> bool205 pub fn is_error(self) -> bool { 206 self.contains(Ready::ERROR) 207 } 208 209 /// Returns true if `self` is a superset of `other`. 210 /// 211 /// `other` may represent more than one readiness operations, in which case 212 /// the function only returns true if `self` contains all readiness 213 /// specified in `other`. contains<T: Into<Self>>(self, other: T) -> bool214 pub(crate) fn contains<T: Into<Self>>(self, other: T) -> bool { 215 let other = other.into(); 216 (self & other) == other 217 } 218 219 /// Creates a `Ready` instance using the given `usize` representation. 220 /// 221 /// The `usize` representation must have been obtained from a call to 222 /// `Readiness::as_usize`. 223 /// 224 /// This function is mainly provided to allow the caller to get a 225 /// readiness value from an `AtomicUsize`. from_usize(val: usize) -> Ready226 pub(crate) fn from_usize(val: usize) -> Ready { 227 Ready(val & Ready::ALL.as_usize()) 228 } 229 230 /// Returns a `usize` representation of the `Ready` value. 231 /// 232 /// This function is mainly provided to allow the caller to store a 233 /// readiness value in an `AtomicUsize`. as_usize(self) -> usize234 pub(crate) fn as_usize(self) -> usize { 235 self.0 236 } 237 from_interest(interest: Interest) -> Ready238 pub(crate) fn from_interest(interest: Interest) -> Ready { 239 let mut ready = Ready::EMPTY; 240 241 if interest.is_readable() { 242 ready |= Ready::READABLE; 243 ready |= Ready::READ_CLOSED; 244 } 245 246 if interest.is_writable() { 247 ready |= Ready::WRITABLE; 248 ready |= Ready::WRITE_CLOSED; 249 } 250 251 #[cfg(any(target_os = "linux", target_os = "android"))] 252 if interest.is_priority() { 253 ready |= Ready::PRIORITY; 254 ready |= Ready::READ_CLOSED; 255 } 256 257 if interest.is_error() { 258 ready |= Ready::ERROR; 259 } 260 261 ready 262 } 263 intersection(self, interest: Interest) -> Ready264 pub(crate) fn intersection(self, interest: Interest) -> Ready { 265 Ready(self.0 & Ready::from_interest(interest).0) 266 } 267 satisfies(self, interest: Interest) -> bool268 pub(crate) fn satisfies(self, interest: Interest) -> bool { 269 self.0 & Ready::from_interest(interest).0 != 0 270 } 271 } 272 273 impl ops::BitOr<Ready> for Ready { 274 type Output = Ready; 275 276 #[inline] bitor(self, other: Ready) -> Ready277 fn bitor(self, other: Ready) -> Ready { 278 Ready(self.0 | other.0) 279 } 280 } 281 282 impl ops::BitOrAssign<Ready> for Ready { 283 #[inline] bitor_assign(&mut self, other: Ready)284 fn bitor_assign(&mut self, other: Ready) { 285 self.0 |= other.0; 286 } 287 } 288 289 impl ops::BitAnd<Ready> for Ready { 290 type Output = Ready; 291 292 #[inline] bitand(self, other: Ready) -> Ready293 fn bitand(self, other: Ready) -> Ready { 294 Ready(self.0 & other.0) 295 } 296 } 297 298 impl ops::Sub<Ready> for Ready { 299 type Output = Ready; 300 301 #[inline] sub(self, other: Ready) -> Ready302 fn sub(self, other: Ready) -> Ready { 303 Ready(self.0 & !other.0) 304 } 305 } 306 307 impl fmt::Debug for Ready { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result308 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 309 let mut fmt = fmt.debug_struct("Ready"); 310 311 fmt.field("is_readable", &self.is_readable()) 312 .field("is_writable", &self.is_writable()) 313 .field("is_read_closed", &self.is_read_closed()) 314 .field("is_write_closed", &self.is_write_closed()) 315 .field("is_error", &self.is_error()); 316 317 #[cfg(any(target_os = "linux", target_os = "android"))] 318 fmt.field("is_priority", &self.is_priority()); 319 320 fmt.finish() 321 } 322 } 323