1use std::{
2 cell::RefCell,
3 io,
4 ops::Deref,
5 pin::Pin,
6 task::{Context, Poll, Waker},
7 time::Duration,
8};
9
10use compio::{compat::Adapter, driver::AsRawFd, runtime::Runtime};
11use windows_sys::Win32::Foundation::HANDLE;
12
13pub struct CompioAdapter {
14 runtime: Runtime,
15}
16
17impl Adapter for CompioAdapter {
18 fn new(runtime: Runtime) -> io::Result<Self> {
19 Ok(Self { runtime })
20 }
21
22 async fn wait(&self, timeout: Option<Duration>) -> io::Result<()> {
23 HandleFuture::new(self.runtime.as_raw_fd(), timeout).await
24 }
25
26 fn clear(&self) -> io::Result<()> {
27 Ok(())
28 }
29}
30
31impl Deref for CompioAdapter {
32 type Target = Runtime;
33
34 fn deref(&self) -> &Self::Target {
35 &self.runtime
36 }
37}
38
39struct HandleFuture {
40 handle: HANDLE,
41 timeout: Option<Duration>,
42 polled: bool,
43}
44
45impl HandleFuture {
46 fn new(handle: HANDLE, timeout: Option<Duration>) -> Self {
47 Self {
48 handle,
49 timeout,
50 polled: false,
51 }
52 }
53}
54
55impl Future for HandleFuture {
56 type Output = io::Result<()>;
57
58 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
59 if self.polled {
60 Poll::Ready(Ok(()))
61 } else {
62 set_context(self.handle, self.timeout, cx.waker().clone());
63 self.polled = true;
64 Poll::Pending
65 }
66 }
67}
68
69impl Drop for HandleFuture {
70 fn drop(&mut self) {
71 reset_context();
72 }
73}
74
75struct HandleContext {
76 handle: HANDLE,
77 timeout: Option<Duration>,
78 waker: Waker,
79}
80
81thread_local! {
82 static CONTEXT: RefCell<Option<HandleContext>> = const { RefCell::new(None) };
83}
84
85fn set_context(handle: HANDLE, timeout: Option<Duration>, waker: Waker) {
86 CONTEXT.with_borrow_mut(|ctx| {
87 ctx.replace(HandleContext {
88 handle,
89 timeout,
90 waker,
91 })
92 });
93}
94
95fn reset_context() {
96 CONTEXT.with_borrow_mut(|ctx| ctx.take());
97}
98
99pub(crate) fn get_handle() -> (Option<HANDLE>, Option<Duration>, Option<Waker>) {
100 CONTEXT.with_borrow(|ctx| {
101 if let Some(ctx) = ctx.as_ref() {
102 (Some(ctx.handle), ctx.timeout, Some(ctx.waker.clone()))
103 } else {
104 (None, None, None)
105 }
106 })
107}