Skip to main content

winio_callback/
lib.rs

1//! A callback helper for async.
2
3#![cfg_attr(docsrs, feature(doc_cfg))]
4#![warn(missing_docs)]
5
6use std::{
7    cell::RefCell,
8    future::Future,
9    hint::unreachable_unchecked,
10    pin::Pin,
11    sync::Mutex,
12    task::{Context, Poll, Waker},
13};
14
15/// An abstract for global runtime.
16pub trait Runnable {
17    /// It will be called if the callback is signaled, and there's a waker to be
18    /// waked.
19    fn run();
20}
21
22impl Runnable for () {
23    fn run() {}
24}
25
26#[derive(Debug)]
27enum WakerState<T> {
28    Inactive,
29    Active(Waker),
30    Signaled(T),
31}
32
33/// A callback type. It is usually signaled in a GUI widget callback.
34#[derive(Debug)]
35pub struct Callback<T = ()>(RefCell<WakerState<T>>);
36
37impl<T> Default for Callback<T> {
38    fn default() -> Self {
39        Self::new()
40    }
41}
42
43impl<T> Callback<T> {
44    /// Create [`Callback`].
45    pub fn new() -> Self {
46        Self(RefCell::new(WakerState::Inactive))
47    }
48
49    /// Signal the callback and try to run the runtime if there's a waker
50    /// waiting. Returns `true` if not handled.
51    pub fn signal<R: Runnable>(&self, v: T) -> bool {
52        let mut state = self.0.borrow_mut();
53        match &*state {
54            WakerState::Inactive => return true,
55            WakerState::Signaled(_) => {
56                // If a state is signaled again, the runtime might be too busy
57                // to wake the waker. Just try to run it again.
58            }
59            WakerState::Active(waker) => {
60                waker.wake_by_ref();
61            }
62        }
63        *state = WakerState::Signaled(v);
64        drop(state);
65        R::run();
66        false
67    }
68
69    pub(crate) fn register(&self, waker: &Waker) -> Poll<T> {
70        let mut state = self.0.borrow_mut();
71        match &*state {
72            WakerState::Signaled(_) => {
73                let state = std::mem::replace(&mut *state, WakerState::Inactive);
74                let v = if let WakerState::Signaled(v) = state {
75                    v
76                } else {
77                    // SAFETY: already checked
78                    unsafe { unreachable_unchecked() }
79                };
80                Poll::Ready(v)
81            }
82            _ => {
83                *state = WakerState::Active(waker.clone());
84                Poll::Pending
85            }
86        }
87    }
88
89    /// Wait for signal.
90    pub fn wait(&self) -> impl Future<Output = T> + '_ {
91        WaitFut(self)
92    }
93}
94
95struct WaitFut<'a, T>(&'a Callback<T>);
96
97impl<T> Future for WaitFut<'_, T> {
98    type Output = T;
99
100    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
101        self.0.register(cx.waker())
102    }
103}
104
105impl<T> Drop for WaitFut<'_, T> {
106    fn drop(&mut self) {
107        // Deregister the waker.
108        *self.0.0.borrow_mut() = WakerState::Inactive;
109    }
110}
111
112/// A thread-safe callback type.
113#[derive(Debug)]
114pub struct SyncCallback<T = ()>(Mutex<WakerState<T>>);
115
116impl<T> Default for SyncCallback<T> {
117    fn default() -> Self {
118        Self::new()
119    }
120}
121
122impl<T> SyncCallback<T> {
123    /// Create [`SyncCallback`].
124    pub fn new() -> Self {
125        Self(Mutex::new(WakerState::Inactive))
126    }
127
128    /// Signal the callback and try to run the runtime if there's a waker
129    /// waiting. Returns `true` if not handled.
130    pub fn signal(&self, v: T) -> bool {
131        let mut state = self.0.lock().unwrap();
132        match &*state {
133            WakerState::Inactive => return true,
134            WakerState::Signaled(_) => {
135                // If a state is signaled again, the runtime might be too busy
136                // to wake the waker. Just try to run it again.
137            }
138            WakerState::Active(waker) => {
139                waker.wake_by_ref();
140            }
141        }
142        *state = WakerState::Signaled(v);
143        false
144    }
145
146    pub(crate) fn register(&self, waker: &Waker) -> Poll<T> {
147        let mut state = self.0.lock().unwrap();
148        match &*state {
149            WakerState::Signaled(_) => {
150                let state = std::mem::replace(&mut *state, WakerState::Inactive);
151                let v = if let WakerState::Signaled(v) = state {
152                    v
153                } else {
154                    // SAFETY: already checked
155                    unsafe { unreachable_unchecked() }
156                };
157                Poll::Ready(v)
158            }
159            _ => {
160                *state = WakerState::Active(waker.clone());
161                Poll::Pending
162            }
163        }
164    }
165
166    /// Wait for signal.
167    pub fn wait(&self) -> impl Future<Output = T> + '_ {
168        SyncWaitFut(self)
169    }
170}
171
172struct SyncWaitFut<'a, T>(&'a SyncCallback<T>);
173
174impl<T> Future for SyncWaitFut<'_, T> {
175    type Output = T;
176
177    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
178        self.0.register(cx.waker())
179    }
180}
181
182impl<T> Drop for SyncWaitFut<'_, T> {
183    fn drop(&mut self) {
184        // Deregister the waker.
185        *self.0.0.lock().unwrap() = WakerState::Inactive;
186    }
187}