compio_runtime/fd/poll_fd/
mod.rs1cfg_select! {
2 windows => {
3 #[path = "windows.rs"]
4 mod sys;
5 }
6 unix => {
7 #[path = "unix.rs"]
8 mod sys;
9 }
10 _ => {}
11}
12
13#[cfg(windows)]
14use std::os::windows::io::{AsRawSocket, RawSocket};
15use std::{
16 future::poll_fn,
17 io,
18 ops::Deref,
19 pin::Pin,
20 task::{Context, Poll},
21};
22
23use compio_buf::IntoInner;
24use compio_driver::{AsFd, AsRawFd, BorrowedFd, RawFd, SharedFd, ToSharedFd};
25
26#[derive(Debug)]
28pub struct PollFd<T: AsFd>(sys::PollFd<T>);
29
30impl<T: AsFd> PollFd<T> {
31 pub fn new(source: T) -> io::Result<Self> {
35 Self::from_shared_fd(SharedFd::new(source))
36 }
37
38 pub fn from_shared_fd(inner: SharedFd<T>) -> io::Result<Self> {
40 Ok(Self(sys::PollFd::new(inner)?))
41 }
42}
43
44impl<T: AsFd + 'static> PollFd<T> {
45 pub async fn accept_ready(&self) -> io::Result<()> {
48 poll_fn(|cx| self.poll_accept_ready(cx)).await
49 }
50
51 pub async fn connect_ready(&self) -> io::Result<()> {
53 poll_fn(|cx| self.poll_connect_ready(cx)).await
54 }
55
56 pub async fn read_ready(&self) -> io::Result<()> {
58 poll_fn(|cx| self.poll_read_ready(cx)).await
59 }
60
61 pub async fn write_ready(&self) -> io::Result<()> {
63 poll_fn(|cx| self.poll_write_ready(cx)).await
64 }
65
66 pub fn poll_accept_ready(&self, cx: &mut Context) -> Poll<io::Result<()>> {
68 self.0.poll_accept_ready(cx)
69 }
70
71 pub fn poll_connect_ready(&self, cx: &mut Context) -> Poll<io::Result<()>> {
73 self.0.poll_connect_ready(cx)
74 }
75
76 pub fn poll_read_ready(&self, cx: &mut Context) -> Poll<io::Result<()>> {
78 self.0.poll_read_ready(cx)
79 }
80
81 pub fn poll_write_ready(&self, cx: &mut Context) -> Poll<io::Result<()>> {
83 self.0.poll_write_ready(cx)
84 }
85
86 pub fn poll_accept_with<R>(
88 &self,
89 cx: &mut Context,
90 mut f: impl FnMut(&T) -> io::Result<R>,
91 ) -> Poll<io::Result<R>> {
92 loop {
93 match f(&self.0) {
94 Ok(result) => break Poll::Ready(Ok(result)),
95 Err(e) if is_would_block(&e) => {
96 std::task::ready!(self.poll_accept_ready(cx))?;
97 }
98 Err(e) => break Poll::Ready(Err(e)),
99 }
100 }
101 }
102
103 pub fn poll_read_with<R>(
105 &self,
106 cx: &mut Context,
107 mut f: impl FnMut(&T) -> io::Result<R>,
108 ) -> Poll<io::Result<R>> {
109 loop {
110 match f(&self.0) {
111 Ok(result) => break Poll::Ready(Ok(result)),
112 Err(e) if is_would_block(&e) => {
113 std::task::ready!(self.poll_read_ready(cx))?;
114 }
115 Err(e) => break Poll::Ready(Err(e)),
116 }
117 }
118 }
119
120 pub fn poll_write_with<R>(
122 &self,
123 cx: &mut Context,
124 mut f: impl FnMut(&T) -> io::Result<R>,
125 ) -> Poll<io::Result<R>> {
126 loop {
127 match f(&self.0) {
128 Ok(result) => break Poll::Ready(Ok(result)),
129 Err(e) if is_would_block(&e) => {
130 std::task::ready!(self.poll_write_ready(cx))?;
131 }
132 Err(e) => break Poll::Ready(Err(e)),
133 }
134 }
135 }
136}
137
138impl<T: AsFd + 'static> PollFd<T>
139where
140 for<'a> &'a T: std::io::Read,
141{
142 pub fn poll_read(&self, cx: &mut Context, buf: &mut [u8]) -> Poll<io::Result<usize>> {
144 self.poll_read_with(cx, |fd| std::io::Read::read(&mut &*fd, buf))
145 }
146
147 #[cfg(feature = "read_buf")]
149 pub fn poll_read_buf(
150 &self,
151 cx: &mut Context,
152 mut buf: std::io::BorrowedCursor<u8>,
153 ) -> Poll<io::Result<()>> {
154 self.poll_read_with(cx, |fd| std::io::Read::read_buf(&mut &*fd, buf.reborrow()))
155 }
156}
157
158impl<T: AsFd + 'static> PollFd<T>
159where
160 for<'a> &'a T: std::io::Write,
161{
162 pub fn poll_write(&self, cx: &mut Context<'_>, buf: &[u8]) -> Poll<io::Result<usize>> {
164 self.poll_write_with(cx, |fd| std::io::Write::write(&mut &*fd, buf))
165 }
166
167 pub fn poll_write_vectored(
175 &self,
176 cx: &mut Context<'_>,
177 bufs: &[io::IoSlice<'_>],
178 ) -> Poll<io::Result<usize>> {
179 self.poll_write_with(cx, |fd| std::io::Write::write_vectored(&mut &*fd, bufs))
180 }
181
182 pub fn poll_flush(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
184 self.poll_write_with(cx, |fd| std::io::Write::flush(&mut &*fd))
185 }
186}
187
188impl<T: AsFd> PollFd<T> {
189 fn shutdown_write(&self) -> io::Result<()> {
198 match sys::shutdown_write(self.0.as_fd()) {
199 Err(e) if is_not_a_connected_socket(&e) => Ok(()),
201 result => result,
202 }
203 }
204}
205
206impl<T: AsFd> IntoInner for PollFd<T> {
207 type Inner = SharedFd<T>;
208
209 fn into_inner(self) -> Self::Inner {
210 self.0.into_inner()
211 }
212}
213
214impl<T: AsFd> ToSharedFd<T> for PollFd<T> {
215 fn to_shared_fd(&self) -> SharedFd<T> {
216 self.0.to_shared_fd()
217 }
218}
219
220impl<T: AsFd> AsFd for PollFd<T> {
221 fn as_fd(&self) -> BorrowedFd<'_> {
222 self.0.as_fd()
223 }
224}
225
226impl<T: AsFd> AsRawFd for PollFd<T> {
227 fn as_raw_fd(&self) -> RawFd {
228 self.0.as_raw_fd()
229 }
230}
231
232#[cfg(windows)]
233impl<T: AsFd + AsRawSocket> AsRawSocket for PollFd<T> {
234 fn as_raw_socket(&self) -> RawSocket {
235 self.0.as_raw_socket()
236 }
237}
238
239impl<T: AsFd> Deref for PollFd<T> {
240 type Target = T;
241
242 fn deref(&self) -> &Self::Target {
243 &self.0
244 }
245}
246
247fn is_would_block(e: &io::Error) -> bool {
248 #[cfg(unix)]
249 {
250 e.kind() == io::ErrorKind::WouldBlock || e.raw_os_error() == Some(libc::EINPROGRESS)
251 }
252 #[cfg(not(unix))]
253 {
254 e.kind() == io::ErrorKind::WouldBlock
255 }
256}
257
258fn is_not_a_connected_socket(e: &io::Error) -> bool {
261 cfg_select! {
262 unix => {
263 matches!(
264 e.raw_os_error(),
265 Some(libc::ENOTSOCK) | Some(libc::ENOTCONN)
266 )
267 }
268 windows => {
269 use windows_sys::Win32::Networking::WinSock::{WSAENOTCONN, WSAENOTSOCK};
270
271 matches!(e.raw_os_error(), Some(WSAENOTSOCK) | Some(WSAENOTCONN))
272 }
273 }
274}
275
276impl<T: AsFd + 'static> futures_util::AsyncRead for &PollFd<T>
277where
278 for<'a> &'a T: std::io::Read,
279{
280 fn poll_read(
281 self: Pin<&mut Self>,
282 cx: &mut Context<'_>,
283 buf: &mut [u8],
284 ) -> Poll<io::Result<usize>> {
285 (*self).poll_read(cx, buf)
286 }
287}
288
289impl<T: AsFd + 'static> futures_util::AsyncRead for PollFd<T>
290where
291 for<'a> &'a T: std::io::Read,
292{
293 fn poll_read(
294 self: Pin<&mut Self>,
295 cx: &mut Context<'_>,
296 buf: &mut [u8],
297 ) -> Poll<io::Result<usize>> {
298 (*self).poll_read(cx, buf)
299 }
300}
301
302impl<T: AsFd + 'static> futures_util::AsyncWrite for &PollFd<T>
303where
304 for<'a> &'a T: std::io::Write,
305{
306 fn poll_write(
307 self: Pin<&mut Self>,
308 cx: &mut Context<'_>,
309 buf: &[u8],
310 ) -> Poll<io::Result<usize>> {
311 (*self).poll_write(cx, buf)
312 }
313
314 fn poll_write_vectored(
315 self: Pin<&mut Self>,
316 cx: &mut Context<'_>,
317 bufs: &[io::IoSlice<'_>],
318 ) -> Poll<io::Result<usize>> {
319 (*self).poll_write_vectored(cx, bufs)
320 }
321
322 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
323 (*self).poll_flush(cx)
324 }
325
326 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
327 Poll::Ready(self.shutdown_write())
330 }
331}
332
333impl<T: AsFd + 'static> futures_util::AsyncWrite for PollFd<T>
334where
335 for<'a> &'a T: std::io::Write,
336{
337 fn poll_write(
338 self: Pin<&mut Self>,
339 cx: &mut Context<'_>,
340 buf: &[u8],
341 ) -> Poll<io::Result<usize>> {
342 (*self).poll_write(cx, buf)
343 }
344
345 fn poll_write_vectored(
346 self: Pin<&mut Self>,
347 cx: &mut Context<'_>,
348 bufs: &[io::IoSlice<'_>],
349 ) -> Poll<io::Result<usize>> {
350 (*self).poll_write_vectored(cx, bufs)
351 }
352
353 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
354 (*self).poll_flush(cx)
355 }
356
357 fn poll_close(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<io::Result<()>> {
358 Poll::Ready(self.shutdown_write())
361 }
362}