Skip to main content

winit/platform_impl/web/async/
wrapper.rs

1use super::super::main_thread::MainThreadMarker;
2use std::cell::{Ref, RefCell};
3use std::future::Future;
4use std::marker::PhantomData;
5use std::sync::Arc;
6
7// Unsafe wrapper type that allows us to use `T` when it's not `Send` from other threads.
8// `value` **must** only be accessed on the main thread.
9pub struct Wrapper<V: 'static, S: Clone + Send, E> {
10    value: Value<V>,
11    handler: fn(&RefCell<Option<V>>, E),
12    sender_data: S,
13    sender_handler: fn(&S, E),
14}
15
16struct Value<V> {
17    // SAFETY:
18    // This value must not be accessed if not on the main thread.
19    //
20    // - We wrap this in an `Arc` to allow it to be safely cloned without accessing the value.
21    // - The `RefCell` lets us mutably access in the main thread but is safe to drop in any thread
22    //   because it has no `Drop` behavior.
23    // - The `Option` lets us safely drop `T` only in the main thread.
24    value: Arc<RefCell<Option<V>>>,
25    // Prevent's `Send` or `Sync` to be automatically implemented.
26    local: PhantomData<*const ()>,
27}
28
29// SAFETY: See `Self::value`.
30unsafe impl<V> Send for Value<V> {}
31// SAFETY: See `Self::value`.
32unsafe impl<V> Sync for Value<V> {}
33
34impl<V, S: Clone + Send, E> Wrapper<V, S, E> {
35    #[track_caller]
36    pub fn new<R: Future<Output = ()>>(
37        _: MainThreadMarker,
38        value: V,
39        handler: fn(&RefCell<Option<V>>, E),
40        receiver: impl 'static + FnOnce(Arc<RefCell<Option<V>>>) -> R,
41        sender_data: S,
42        sender_handler: fn(&S, E),
43    ) -> Option<Self> {
44        let value = Arc::new(RefCell::new(Some(value)));
45
46        wasm_bindgen_futures::spawn_local({
47            let value = Arc::clone(&value);
48            async move {
49                receiver(Arc::clone(&value)).await;
50                drop(value.borrow_mut().take().unwrap());
51            }
52        });
53
54        Some(Self {
55            value: Value { value, local: PhantomData },
56            handler,
57            sender_data,
58            sender_handler,
59        })
60    }
61
62    pub fn send(&self, event: E) {
63        if MainThreadMarker::new().is_some() {
64            (self.handler)(&self.value.value, event)
65        } else {
66            (self.sender_handler)(&self.sender_data, event)
67        }
68    }
69
70    pub fn value(&self) -> Option<Ref<'_, V>> {
71        MainThreadMarker::new()
72            .map(|_| Ref::map(self.value.value.borrow(), |value| value.as_ref().unwrap()))
73    }
74
75    pub fn with_sender_data<T>(&self, f: impl FnOnce(&S) -> T) -> T {
76        f(&self.sender_data)
77    }
78}
79
80impl<V, S: Clone + Send, E> Clone for Wrapper<V, S, E> {
81    fn clone(&self) -> Self {
82        Self {
83            value: Value { value: self.value.value.clone(), local: PhantomData },
84            handler: self.handler,
85            sender_data: self.sender_data.clone(),
86            sender_handler: self.sender_handler,
87        }
88    }
89}