1use crate::waker::WakerList;
7use std::fmt;
8use std::fmt::Debug;
9use std::task::Context;
10use std::task::Poll;
11use std::task::Waker;
12
13#[derive(Copy, Clone, Default, PartialEq, Eq)]
15pub struct PollEvents(u32);
16
17impl Debug for PollEvents {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 let mut list = f.debug_set();
20 if self.has_in() {
21 list.entry(&format_args!("IN"));
22 }
23 if self.has_out() {
24 list.entry(&format_args!("OUT"));
25 }
26 if self.has_err() {
27 list.entry(&format_args!("ERR"));
28 }
29 if self.has_hup() {
30 list.entry(&format_args!("HUP"));
31 }
32 if self.has_pri() {
33 list.entry(&format_args!("PRI"));
34 }
35 #[cfg(any(windows, target_os = "linux"))]
36 if self.has_rdhup() {
37 list.entry(&format_args!("RDHUP"));
38 }
39 list.finish()
40 }
41}
42
43impl PollEvents {
44 pub const EMPTY: Self = Self(0);
46 pub const FULL: Self = Self(0x3f);
48 pub const IN: Self = Self(0x1);
50 pub const OUT: Self = Self(0x2);
52 pub const ERR: Self = Self(0x4);
54 pub const HUP: Self = Self(0x8);
56 pub const PRI: Self = Self(0x10);
58 pub const RDHUP: Self = Self(0x20);
60
61 pub fn is_empty(self) -> bool {
63 self.0 == 0
64 }
65
66 pub fn has_in(self) -> bool {
68 self.0 & Self::IN.0 != 0
69 }
70
71 pub fn has_out(self) -> bool {
73 self.0 & Self::OUT.0 != 0
74 }
75
76 pub fn has_err(self) -> bool {
78 self.0 & Self::ERR.0 != 0
79 }
80
81 pub fn has_hup(self) -> bool {
83 self.0 & Self::HUP.0 != 0
84 }
85
86 pub fn has_pri(self) -> bool {
88 self.0 & Self::PRI.0 != 0
89 }
90
91 #[cfg(any(windows, target_os = "linux"))]
93 pub fn has_rdhup(self) -> bool {
94 self.0 & Self::RDHUP.0 != 0
95 }
96}
97
98impl std::ops::Not for PollEvents {
99 type Output = Self;
100
101 fn not(self) -> Self::Output {
102 Self(!self.0) & Self::FULL
103 }
104}
105
106impl std::ops::BitOr for PollEvents {
107 type Output = Self;
108
109 fn bitor(self, rhs: Self) -> Self::Output {
110 Self(self.0 | rhs.0)
111 }
112}
113
114impl std::ops::BitOrAssign for PollEvents {
115 fn bitor_assign(&mut self, rhs: Self) {
116 self.0 |= rhs.0;
117 }
118}
119
120impl std::ops::BitAnd for PollEvents {
121 type Output = Self;
122
123 fn bitand(self, rhs: Self) -> Self::Output {
124 Self(self.0 & rhs.0)
125 }
126}
127
128impl std::ops::BitAndAssign for PollEvents {
129 fn bitand_assign(&mut self, rhs: Self) {
130 self.0 &= rhs.0;
131 }
132}
133
134impl PollEvents {
135 #[cfg(unix)]
137 pub fn to_poll_events(self) -> i16 {
138 let mut poll_events = 0;
139 if self.has_in() {
140 poll_events |= libc::POLLIN;
141 }
142 if self.has_out() {
143 poll_events |= libc::POLLOUT;
144 }
145 if self.has_pri() {
146 poll_events |= libc::POLLPRI;
147 }
148 if self.has_hup() {
149 poll_events |= libc::POLLHUP;
150 }
151 if self.has_err() {
152 poll_events |= libc::POLLERR;
153 }
154 #[cfg(target_os = "linux")]
155 if self.has_rdhup() {
156 poll_events |= libc::POLLRDHUP;
157 }
158 poll_events
159 }
160
161 #[cfg(unix)]
163 pub fn from_poll_events(poll_events: i16) -> Self {
164 let mut events = PollEvents::EMPTY;
165 if poll_events & libc::POLLHUP != 0 {
166 events |= PollEvents::HUP;
167 }
168 if poll_events & libc::POLLERR != 0 {
169 events |= PollEvents::ERR;
170 }
171 if poll_events & libc::POLLIN != 0 {
172 events |= PollEvents::IN;
173 }
174 if poll_events & libc::POLLOUT != 0 {
175 events |= PollEvents::OUT;
176 }
177 if poll_events & libc::POLLPRI != 0 {
178 events |= PollEvents::PRI;
179 }
180 #[cfg(target_os = "linux")]
181 if poll_events & libc::POLLRDHUP != 0 {
182 events |= PollEvents::RDHUP;
183 }
184 events
185 }
186
187 #[cfg(target_os = "linux")]
188 pub(crate) fn from_epoll_events(epoll_events: u32) -> Self {
189 let mut events = PollEvents::EMPTY;
190 if epoll_events & libc::EPOLLIN as u32 != 0 {
191 events |= PollEvents::IN;
192 }
193 if epoll_events & libc::EPOLLOUT as u32 != 0 {
194 events |= PollEvents::OUT;
195 }
196 if epoll_events & libc::EPOLLERR as u32 != 0 {
197 events |= PollEvents::ERR;
198 }
199 if epoll_events & libc::EPOLLHUP as u32 != 0 {
200 events |= PollEvents::HUP;
201 }
202 if epoll_events & libc::EPOLLPRI as u32 != 0 {
203 events |= PollEvents::PRI;
204 }
205 if epoll_events & libc::EPOLLRDHUP as u32 != 0 {
206 events |= PollEvents::RDHUP;
207 }
208 events
209 }
210}
211
212#[derive(Debug, Default)]
213struct PollInterest {
214 events: PollEvents,
215 observed_revents: PollEvents,
216 delivered_revents: PollEvents,
217 waker: Option<Waker>,
218}
219
220#[derive(Debug, Copy, Clone, PartialEq, Eq)]
229pub enum InterestSlot {
230 Read = 0,
232 Write = 1,
234}
235
236pub const SLOT_COUNT: usize = 2;
238
239#[derive(Debug, Default)]
241pub(crate) struct PollInterestSet([PollInterest; SLOT_COUNT]);
242
243impl PollInterestSet {
244 pub fn poll_ready(
245 &mut self,
246 cx: &mut Context<'_>,
247 slot: InterestSlot,
248 events: PollEvents,
249 ) -> Poll<PollEvents> {
250 let interest = &mut self.0[slot as usize];
251 let events = events | PollEvents::HUP | PollEvents::ERR;
253 let revents = (interest.observed_revents | interest.delivered_revents) & events;
254 if !revents.is_empty() {
255 interest.events = PollEvents::EMPTY;
256 interest.observed_revents |= revents;
257 interest.delivered_revents &= !revents;
258 Poll::Ready(revents)
259 } else {
260 interest.events = events;
261 if !interest
262 .waker
263 .as_ref()
264 .is_some_and(|w| w.will_wake(cx.waker()))
265 {
266 interest.waker = Some(cx.waker().clone());
267 }
268 Poll::Pending
269 }
270 }
271
272 #[cfg(windows)]
273 pub fn clear_all(&mut self) {
274 *self = Default::default();
275 }
276
277 pub fn clear_ready(&mut self, slot: InterestSlot) {
278 let interest = &mut self.0[slot as usize];
279 interest.events = PollEvents::EMPTY;
280 interest.observed_revents = PollEvents::EMPTY;
281 }
282
283 pub fn events_to_poll(&self) -> PollEvents {
284 self.0.iter().fold(PollEvents::EMPTY, |e, p| {
285 e | if ((p.observed_revents | p.delivered_revents) & p.events).is_empty() {
286 p.events
287 } else {
288 PollEvents::EMPTY
289 }
290 })
291 }
292
293 pub fn wake_ready(&mut self, revents: PollEvents, wakers: &mut WakerList) {
294 wakers.extend(self.0.iter_mut().filter_map(|p| {
295 p.delivered_revents |= revents;
296 if !(p.events & revents).is_empty() {
297 p.waker.take()
298 } else {
299 None
300 }
301 }))
302 }
303}