netwatcher/
async_adapter.rs1use std::{future::Future, pin::Pin};
2
3#[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
4use std::marker::PhantomData;
5
6#[cfg(all(
7 any(feature = "async-io", feature = "tokio"),
8 any(target_os = "linux", target_vendor = "apple")
9))]
10use std::io;
11#[cfg(all(
12 any(feature = "async-io", feature = "tokio"),
13 any(target_os = "linux", target_vendor = "apple")
14))]
15use std::os::fd::AsFd;
16#[cfg(any(target_os = "linux", target_vendor = "apple"))]
17use std::os::fd::{BorrowedFd, OwnedFd};
18
19pub struct AsyncFd {
24 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
25 inner: OwnedFd,
26 #[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
27 _private: (),
28}
29
30impl AsyncFd {
31 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
32 pub(crate) fn from_owned_fd(inner: OwnedFd) -> Self {
33 Self { inner }
34 }
35
36 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
37 pub fn into_owned_fd(self) -> OwnedFd {
38 self.inner
39 }
40}
41
42pub struct AsyncFdRef<'a> {
47 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
48 inner: BorrowedFd<'a>,
49 #[cfg(not(any(target_os = "linux", target_vendor = "apple")))]
50 _marker: PhantomData<&'a ()>,
51}
52
53impl<'a> AsyncFdRef<'a> {
54 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
55 pub fn from_borrowed_fd(inner: BorrowedFd<'a>) -> Self {
56 Self { inner }
57 }
58
59 #[cfg(any(target_os = "linux", target_vendor = "apple"))]
60 pub fn as_fd(&self) -> BorrowedFd<'_> {
61 self.inner
62 }
63}
64
65pub trait AsyncFdAdapter {
70 fn register(fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>>;
71}
72
73pub type AsyncFdReadableFuture<'a> =
74 Pin<Box<dyn Future<Output = std::io::Result<Box<dyn AsyncFdReadyGuard + 'a>>> + 'a>>;
75
76pub trait AsyncFdRegistration: Send + Sync {
78 fn readable(&self) -> AsyncFdReadableFuture<'_>;
79}
80
81pub trait AsyncFdReadyGuard {
83 fn fd(&self) -> AsyncFdRef<'_>;
84 fn clear_ready(&mut self);
85}
86
87#[cfg(feature = "async-io")]
88pub struct AsyncIo;
89
90#[cfg(feature = "tokio")]
91pub struct Tokio;
92
93#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
94impl AsyncFdAdapter for Tokio {
95 fn register(fd: AsyncFd) -> io::Result<Box<dyn AsyncFdRegistration>> {
96 Ok(Box::new(tokio::io::unix::AsyncFd::new(fd.into_owned_fd())?))
97 }
98}
99
100#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
101impl AsyncFdRegistration for tokio::io::unix::AsyncFd<OwnedFd> {
102 fn readable(&self) -> AsyncFdReadableFuture<'_> {
103 Box::pin(async move {
104 let guard = self.readable().await?;
105 Ok(Box::new(guard) as Box<dyn AsyncFdReadyGuard>)
106 })
107 }
108}
109
110#[cfg(all(feature = "tokio", any(target_os = "linux", target_vendor = "apple")))]
111impl AsyncFdReadyGuard for tokio::io::unix::AsyncFdReadyGuard<'_, OwnedFd> {
112 fn fd(&self) -> AsyncFdRef<'_> {
113 AsyncFdRef::from_borrowed_fd(self.get_inner().as_fd())
114 }
115
116 fn clear_ready(&mut self) {
117 tokio::io::unix::AsyncFdReadyGuard::clear_ready(self);
118 }
119}
120
121#[cfg(all(feature = "tokio", any(windows, target_os = "android")))]
122impl AsyncFdAdapter for Tokio {
123 fn register(_fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>> {
124 unreachable!("Tokio AsyncFd registration is not used on this platform")
125 }
126}
127
128#[cfg(all(
129 feature = "async-io",
130 any(target_os = "linux", target_vendor = "apple")
131))]
132impl AsyncFdAdapter for AsyncIo {
133 fn register(fd: AsyncFd) -> io::Result<Box<dyn AsyncFdRegistration>> {
134 Ok(Box::new(AsyncIoRegistration(async_io::Async::new(
135 fd.into_owned_fd(),
136 )?)))
137 }
138}
139
140#[cfg(all(
141 feature = "async-io",
142 any(target_os = "linux", target_vendor = "apple")
143))]
144struct AsyncIoRegistration(async_io::Async<OwnedFd>);
145
146#[cfg(all(
147 feature = "async-io",
148 any(target_os = "linux", target_vendor = "apple")
149))]
150struct AsyncIoReadyGuard<'a>(&'a async_io::Async<OwnedFd>);
151
152#[cfg(all(
153 feature = "async-io",
154 any(target_os = "linux", target_vendor = "apple")
155))]
156impl AsyncFdRegistration for AsyncIoRegistration {
157 fn readable(&self) -> AsyncFdReadableFuture<'_> {
158 Box::pin(async move {
159 self.0.readable().await?;
160 Ok(Box::new(AsyncIoReadyGuard(&self.0)) as Box<dyn AsyncFdReadyGuard>)
161 })
162 }
163}
164
165#[cfg(all(
166 feature = "async-io",
167 any(target_os = "linux", target_vendor = "apple")
168))]
169impl AsyncFdReadyGuard for AsyncIoReadyGuard<'_> {
170 fn fd(&self) -> AsyncFdRef<'_> {
171 AsyncFdRef::from_borrowed_fd(self.0.get_ref().as_fd())
172 }
173
174 fn clear_ready(&mut self) {}
175}
176
177#[cfg(all(feature = "async-io", any(windows, target_os = "android")))]
178impl AsyncFdAdapter for AsyncIo {
179 fn register(_fd: AsyncFd) -> std::io::Result<Box<dyn AsyncFdRegistration>> {
180 unreachable!("async-io AsyncFd registration is not used on this platform")
181 }
182}