browser_window/
delegate.rs

1use std::{
2	boxed::Box,
3	future::Future,
4	mem, panic,
5	panic::{catch_unwind, AssertUnwindSafe},
6	pin::Pin,
7	task::{Context, Poll, Waker},
8};
9
10use crate::{application::ApplicationHandle, core::application::*, HasHandle};
11
12
13/// The data that is sent to the GUI thread for `DelegateFuture`.
14struct DelegateData<'a, 'b, O, H, R> {
15	handle: O,
16	result: &'a mut Option<Result<R, DelegateError>>,
17	func: Box<dyn FnOnce(&H) -> R + Send + 'b>,
18	waker: Waker,
19}
20//unsafe impl<'a,H,R> Send for DelegateData<'a,H,R> {}
21
22/// The data that is sent to the GUI thread for `DelegateFutureFuture`.
23struct DelegateFutureData<'a, 'b, R>
24where
25	R: Send,
26{
27	inner: &'b mut DelegateFutureInner<'a, R>,
28	waker: Waker,
29}
30
31/// The error that occurs when you're delegating work to the GUI thread, but it
32/// fails to finish and/or return a result.
33#[derive(Debug)]
34pub enum DelegateError {
35	/// The runtime has either not yet started or already ended.
36	/// This happens when the application has already exited for example.
37	RuntimeNotAvailable,
38	/// The delegated closure has panicked.
39	ClosurePanicked,
40}
41
42/// This future executes a closure on the GUI thread and returns the result.
43pub struct DelegateFuture<'a, O, H, R>
44where
45	R: Send,
46{
47	handle: O,
48	func: Option<Box<dyn FnOnce(&H) -> R + Send + 'a>>,
49	result: Option<Result<R, DelegateError>>,
50	started: bool,
51}
52impl<'a, O, H, R> Unpin for DelegateFuture<'a, O, H, R> where R: Send {}
53/// # Safety
54/// `DelegateFuture` by itself is not send.
55/// This is because we keep a handle `H`, which is not necessarily `Send`.
56/// However, because the closure only executes on the GUI thread,
57///  and because the handle is only provided to the closure that will be
58/// executed on the GUI thread,  this should be fine.
59unsafe impl<'a, O, H, R> Send for DelegateFuture<'a, O, H, R> where R: Send {}
60
61/// This future runs a future on the GUI thread and returns its output.
62pub struct DelegateFutureFuture<'a, R>
63where
64	R: Send,
65{
66	app_handle: ApplicationHandle,
67	inner: DelegateFutureInner<'a, R>,
68	started: bool,
69}
70/// # Safety
71/// `DelegateFutureFuture` by itself is not send.
72/// This is because of `ApplicationHandle`.
73/// However, because the closure only executes on the GUI thread,
74///  and because this handle that is provided to the closure is something that
75/// will only be sent with the closure to the GUI thread,  this should be fine.
76unsafe impl<'a, R> Send for DelegateFutureFuture<'a, R> where R: Send {}
77impl<'a, R> Unpin for DelegateFutureFuture<'a, R> where R: Send {}
78
79/// This is not a future but the inner part that of `DelegateFutureFuture` that
80/// needs to have mutable reference.
81struct DelegateFutureInner<'a, R>
82where
83	R: Send,
84{
85	result: Option<Result<R, DelegateError>>,
86	future: Pin<Box<dyn Future<Output = R> + 'a>>,
87}
88// # Safety
89// `DelegateFutureInner` is marked as `Send` so that `delegate_async` can pass a
90// non-`Send` future into this future. The resulting future from the closure of
91// `delegate_async` does not need to be `Send` because the future is obtained
92// _and_ executed within the GUI thread. `delegate_async` puts a future obtained
93// from an `async` block into `DelegateFutureFuture`, and therefor in
94// `DelegateFutureInner`. However, because the future obtained from the closure
95// is not necessarily `Send`, Rust makes the whole async block non-`Send`.
96// Even though all parts of that `async` block are executed on the same thread
97// in this scenario. This is therefor marked as `Send` on the condition that
98// whenever `DelegateFutureFuture` is constructed,  care should be taken to make
99// sure that the future is safe to send to other threads.
100unsafe impl<'a, R> Send for DelegateFutureInner<'a, R> where R: Send {}
101
102
103#[cfg(feature = "threadsafe")]
104impl<'a, O, H, R> DelegateFuture<'a, O, H, R>
105where
106	R: Send,
107{
108	pub(super) fn new<F>(handle: O, func: F) -> Self
109	where
110		F: FnOnce(&H) -> R + Send + 'a,
111		R: Send,
112	{
113		Self {
114			handle,
115			func: Some(Box::new(func)),
116			result: None,
117			started: false,
118		}
119	}
120}
121
122#[cfg(feature = "threadsafe")]
123impl<'a, O, H, R> Future for DelegateFuture<'a, O, H, R>
124where
125	O: HasHandle<H> + HasHandle<ApplicationHandle> + Clone,
126	H: 'static,
127	R: Send + 'static,
128{
129	type Output = Result<R, DelegateError>;
130
131	fn poll(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
132		if !self.started {
133			self.started = true;
134			let app_inner = HasHandle::<ApplicationHandle>::handle(&self.handle)
135				.inner
136				.clone();
137
138			// Move ownership from `DelegateFuture` to `DelegateData`
139			let mut func = None;
140			mem::swap(&mut self.func, &mut func);
141
142			// Data to provide for the dispatched c function
143			// This includes the closure to actually call,
144			// a pointer to set the output with,
145			// and a waker to finish our future with.
146			let data = DelegateData {
147				handle: self.handle.clone(),
148				func: func.unwrap(),
149				result: &mut self.result,
150				waker: cx.waker().clone(),
151			};
152
153			let succeeded = {
154				let data_ptr = Box::into_raw(Box::new(data));
155
156				app_inner.dispatch(delegate_handler::<O, H, R>, data_ptr as _)
157			};
158
159			// cbw_Application_dispatch fails when there is now runtime that is running
160			if !succeeded {
161				return Poll::Ready(Err(DelegateError::RuntimeNotAvailable));
162			}
163
164			Poll::Pending
165		} else {
166			if self.result.is_none() {
167				return Poll::Pending;
168			}
169
170			// Move ownership of output to temporary value so we can return it
171			let mut temp: Option<Result<R, DelegateError>> = None;
172			mem::swap(&mut self.result, &mut temp);
173
174			Poll::Ready(temp.unwrap())
175		}
176	}
177}
178
179#[cfg(feature = "threadsafe")]
180impl<'a, R> DelegateFutureFuture<'a, R>
181where
182	R: Send,
183{
184	pub(super) fn new(app_handle: ApplicationHandle, future: impl Future<Output = R> + 'a) -> Self {
185		Self {
186			app_handle,
187			inner: DelegateFutureInner {
188				result: None,
189				future: Box::pin(future),
190			},
191			started: false,
192		}
193	}
194}
195
196#[cfg(feature = "threadsafe")]
197impl<'a, R> Future for DelegateFutureFuture<'a, R>
198where
199	R: Send,
200{
201	type Output = Result<R, DelegateError>;
202
203	fn poll(mut self: Pin<&mut Self>, ctx: &mut Context) -> Poll<Self::Output> {
204		// While the result is not yet set, we can keep polling
205		if !self.started {
206			self.started = true;
207			let app_inner = self.app_handle.inner.clone();
208
209			let data_ptr = Box::into_raw(Box::new(DelegateFutureData {
210				inner: &mut self.inner,
211				waker: ctx.waker().clone(),
212			}));
213
214			let succeeded = app_inner.dispatch(delegate_async_handler::<R>, data_ptr as _);
215
216			// cbw_Application_dispatch fails when there is no runtime that is actually
217			// running
218			if !succeeded {
219				return Poll::Ready(Err(DelegateError::RuntimeNotAvailable));
220			}
221
222			Poll::Pending
223		} else {
224			// Move ownership of output to temporary value so we can return it
225			let mut temp: Option<Result<R, DelegateError>> = None;
226			mem::swap(&mut self.inner.result, &mut temp);
227
228			Poll::Ready(temp.unwrap())
229		}
230	}
231}
232
233
234fn delegate_handler<O, H, R>(app: ApplicationImpl, _data: *mut ())
235where
236	H: 'static,
237	O: HasHandle<H>,
238	R: 'static,
239{
240	let data_ptr = _data as *mut DelegateData<'static, 'static, O, H, R>;
241	let data = unsafe { Box::from_raw(data_ptr) }; // Take ownership of the data struct
242
243	match *data {
244		DelegateData {
245			handle,
246			func,
247			result,
248			waker,
249		} => {
250			// Catch Rust panics during execution of delegated function
251			match catch_unwind(AssertUnwindSafe(|| {
252				let h = handle.handle();
253				*result = Some(Ok(func(h)));
254				waker.clone().wake();
255			})) {
256				Ok(()) => {}
257				Err(_) => {
258					*result = Some(Err(DelegateError::ClosurePanicked));
259
260					// Wake the future before exiting. This allows the calling thread to still
261					// receive the `DelegateError` before the application stops working.
262					waker.wake();
263
264					app.exit(-1);
265				}
266			}
267		}
268	}
269}
270
271#[cfg(feature = "threadsafe")]
272fn delegate_async_handler<R>(app: ApplicationImpl, _data: *mut ())
273where
274	R: Send,
275{
276	let data_ptr = _data as *mut DelegateFutureData<R>;
277	let data = unsafe { Box::from_raw(data_ptr) }; // Take ownership of the data struct
278
279	match *data {
280		DelegateFutureData { inner, waker } => {
281			// Catch Rust panics
282			match panic::catch_unwind(AssertUnwindSafe(|| {
283				let mut ctx = Context::from_waker(&waker);
284				match inner.future.as_mut().poll(&mut ctx) {
285					Poll::Pending => {}
286					Poll::Ready(result) => {
287						// Set the result and wake our future so it gets returned
288						inner.result = Some(Ok(result));
289						waker.clone().wake();
290					}
291				}
292			})) {
293				Ok(()) => {}
294				Err(_) => {
295					inner.result = Some(Err(DelegateError::ClosurePanicked));
296
297					// Wake the future before exiting. This allows the calling thread to still
298					// receive the `DelegateError` before the application stops working.
299					waker.wake();
300
301					app.exit(-1);
302				}
303			}
304		}
305	}
306}