Skip to main content

winio_ui_win32/
compat.rs

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}