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