1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
use crate::*;
use std::marker::PhantomData;
use std::sync::Mutex;
/// Run code on the UI thread from another thread.
///
/// Allows you to mix non-blocking threaded code, with code that reads and updates
/// your widget in the UI thread.
///
/// This can be copied and passed around.
pub struct UiRunner<T> {
/// Trick to later distinguish actions sent globally thru `Cx::post_action`.
key: usize,
/// Enforce a consistent `target` type across `handle` and `defer`.
///
/// `fn() -> W` is used instead of `W` because, in summary, these:
/// - https://stackoverflow.com/a/50201389
/// - https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns
/// - https://doc.rust-lang.org/std/marker/struct.PhantomData.html
target: PhantomData<fn() -> T>,
}
impl<T> Copy for UiRunner<T> {}
impl<T> Clone for UiRunner<T> {
fn clone(&self) -> Self {
Self {
key: self.key,
target: PhantomData,
}
}
}
impl<T> std::fmt::Debug for UiRunner<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UiRunner").field("key", &self.key).finish()
}
}
impl<T> PartialEq for UiRunner<T> {
fn eq(&self, other: &Self) -> bool {
self.key == other.key
}
}
impl<T: 'static> UiRunner<T> {
/// Create a new `UiRunner` that dispatches functions as global actions but
/// differentiates them by the provided `key`.
///
/// If used in a widget, prefer using `your_widget.ui_runner()`.
/// If used in your app main, prefer using `your_app_main.ui_runner()`.
pub fn new(key: usize) -> Self {
Self {
key,
target: PhantomData,
}
}
/// Handle all functions scheduled with the `key` of this `UiRunner`.
///
/// You should call this once from your `handle_event` method, like:
///
/// ```rust
/// fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
/// // ... handle other stuff ...
/// self.ui_runner().handle(cx, event, scope, self);
/// }
/// ```
///
/// Once a function has been handled, it will never run again.
pub fn handle(self, cx: &mut Cx, event: &Event, scope: &mut Scope, target: &mut T) {
if let Event::Actions(actions) = event {
for action in actions {
if let Some(action) = action.downcast_ref::<UiRunnerAction<T>>() {
if action.key != self.key {
continue;
}
if let Some(f) = action.f.lock().unwrap().take() {
(f)(target, cx, scope);
}
}
}
}
}
/// Schedule the provided closure to run on the UI thread.
pub fn defer(self, f: impl DeferCallback<T>) {
let action = UiRunnerAction {
f: Mutex::new(Some(Box::new(f))),
key: self.key,
};
Cx::post_action(action);
}
/// Like `defer`, but blocks the current thread until the UI awakes, processes
/// the closure, and returns the result.
///
/// Generally, you should prefer to use `defer` if you don't need to communicate
/// a value back. This method may wait a long time if the UI thread is busy so you
/// should not use it in tight loops.
pub fn block_on<R: Send + 'static>(
self,
f: impl FnOnce(&mut T, &mut Cx, &mut Scope) -> R + Send + 'static,
) -> R {
let (tx, rx) = std::sync::mpsc::channel();
self.defer(move |target, cx, scope| {
tx.send(f(target, cx, scope)).unwrap();
});
rx.recv().unwrap()
}
}
/// Private message that is sent to the ui thread with the closure to run.
struct UiRunnerAction<T> {
f: Mutex<Option<Box<dyn DeferCallback<T>>>>,
key: usize,
}
impl<T> std::fmt::Debug for UiRunnerAction<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UiRunnerAction")
.field("key", &self.key)
.field("f", &"...")
.finish()
}
}
pub trait DeferCallback<T>: FnOnce(&mut T, &mut Cx, &mut Scope) + Send + 'static {}
impl<T, F: FnOnce(&mut T, &mut Cx, &mut Scope) + Send + 'static> DeferCallback<T> for F {}