Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/platform/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ use crate::event_loop::EventLoopWindowTarget;
use crate::platform_impl::PlatformCustomCursorBuilder;
use crate::window::CustomCursor;
use crate::window::{Window, WindowBuilder};
use crate::SendSyncWrapper;

use web_sys::HtmlCanvasElement;

Expand Down Expand Up @@ -105,7 +104,7 @@ pub trait WindowBuilderExtWebSys {

impl WindowBuilderExtWebSys for WindowBuilder {
fn with_canvas(mut self, canvas: Option<HtmlCanvasElement>) -> Self {
self.platform_specific.canvas = SendSyncWrapper(canvas);
self.platform_specific.set_canvas(canvas);
self
}

Expand Down
4 changes: 3 additions & 1 deletion src/platform_impl/web/async/dispatcher.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::super::main_thread::MainThreadMarker;
use super::{channel, AsyncReceiver, AsyncSender, Wrapper};
use std::{
cell::Ref,
Expand All @@ -10,10 +11,11 @@ struct Closure<T>(Box<dyn FnOnce(&T) + Send>);

impl<T> Dispatcher<T> {
#[track_caller]
pub fn new(value: T) -> Option<(Self, DispatchRunner<T>)> {
pub fn new(main_thread: MainThreadMarker, value: T) -> Option<(Self, DispatchRunner<T>)> {
let (sender, receiver) = channel::<Closure<T>>();

Wrapper::new(
main_thread,
value,
|value, Closure(closure)| {
// SAFETY: The given `Closure` here isn't really `'static`, so we shouldn't do anything
Expand Down
6 changes: 4 additions & 2 deletions src/platform_impl/web/async/waker.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use super::super::main_thread::MainThreadMarker;
use super::Wrapper;
use atomic_waker::AtomicWaker;
use std::future;
Expand All @@ -19,7 +20,7 @@ struct Sender(Arc<Inner>);

impl<T> WakerSpawner<T> {
#[track_caller]
pub fn new(value: T, handler: fn(&T, usize)) -> Option<Self> {
pub fn new(main_thread: MainThreadMarker, value: T, handler: fn(&T, usize)) -> Option<Self> {
let inner = Arc::new(Inner {
counter: AtomicUsize::new(0),
waker: AtomicWaker::new(),
Expand All @@ -31,6 +32,7 @@ impl<T> WakerSpawner<T> {
let sender = Sender(Arc::clone(&inner));

let wrapper = Wrapper::new(
main_thread,
handler,
|handler, count| {
let handler = handler.borrow();
Expand Down Expand Up @@ -86,7 +88,7 @@ impl<T> WakerSpawner<T> {

pub fn fetch(&self) -> usize {
debug_assert!(
self.0.is_main_thread(),
MainThreadMarker::new().is_some(),
"this should only be called from the main thread"
);

Expand Down
53 changes: 9 additions & 44 deletions src/platform_impl/web/async/wrapper.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
use super::super::main_thread::MainThreadMarker;
use std::cell::{Ref, RefCell};
use std::future::Future;
use std::marker::PhantomData;
use std::sync::Arc;
use wasm_bindgen::prelude::wasm_bindgen;
use wasm_bindgen::{JsCast, JsValue};

// Unsafe wrapper type that allows us to use `T` when it's not `Send` from other threads.
// `value` **must** only be accessed on the main thread.
Expand Down Expand Up @@ -34,36 +33,15 @@ unsafe impl<const SYNC: bool, V> Send for Value<SYNC, V> {}
unsafe impl<V> Sync for Value<true, V> {}

impl<const SYNC: bool, V, S: Clone + Send, E> Wrapper<SYNC, V, S, E> {
thread_local! {
static MAIN_THREAD: bool = {
#[wasm_bindgen]
extern "C" {
#[derive(Clone)]
type Global;

#[wasm_bindgen(method, getter, js_name = Window)]
fn window(this: &Global) -> JsValue;
}

let global: Global = js_sys::global().unchecked_into();
!global.window().is_undefined()
};
}

#[track_caller]
pub fn new<R: Future<Output = ()>>(
_: MainThreadMarker,
value: V,
handler: fn(&RefCell<Option<V>>, E),
receiver: impl 'static + FnOnce(Arc<RefCell<Option<V>>>) -> R,
sender_data: S,
sender_handler: fn(&S, E),
) -> Option<Self> {
Self::MAIN_THREAD.with(|safe| {
if !safe {
panic!("only callable from inside the `Window`")
}
});

let value = Arc::new(RefCell::new(Some(value)));

wasm_bindgen_futures::spawn_local({
Expand All @@ -86,29 +64,16 @@ impl<const SYNC: bool, V, S: Clone + Send, E> Wrapper<SYNC, V, S, E> {
}

pub fn send(&self, event: E) {
Self::MAIN_THREAD.with(|is_main_thread| {
if *is_main_thread {
(self.handler)(&self.value.value, event)
} else {
(self.sender_handler)(&self.sender_data, event)
}
})
}

pub fn is_main_thread(&self) -> bool {
Self::MAIN_THREAD.with(|is_main_thread| *is_main_thread)
if MainThreadMarker::new().is_some() {
(self.handler)(&self.value.value, event)
} else {
(self.sender_handler)(&self.sender_data, event)
}
}

pub fn value(&self) -> Option<Ref<'_, V>> {
Self::MAIN_THREAD.with(|is_main_thread| {
if *is_main_thread {
Some(Ref::map(self.value.value.borrow(), |value| {
value.as_ref().unwrap()
}))
} else {
None
}
})
MainThreadMarker::new()
.map(|_| Ref::map(self.value.value.borrow(), |value| value.as_ref().unwrap()))
}

pub fn with_sender_data<T>(&self, f: impl FnOnce(&S) -> T) -> T {
Expand Down
Loading