Skip to content

Commit

Permalink
Split Waker into WakerSpawner and Waker
Browse files Browse the repository at this point in the history
  • Loading branch information
daxpedda committed Sep 3, 2023
1 parent 9e2e719 commit eacf2a4
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 36 deletions.
2 changes: 1 addition & 1 deletion src/platform_impl/web/async/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ mod wrapper;

use self::channel::{channel, AsyncSender};
pub use self::dispatcher::Dispatcher;
pub use self::waker::Waker;
pub use self::waker::{Waker, WakerSpawner};
use self::wrapper::Wrapper;
42 changes: 22 additions & 20 deletions src/platform_impl/web/async/waker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::Arc;
use std::task::Poll;

pub struct Waker<T: 'static> {
wrapper: Wrapper<false, Handler<T>, Sender, usize>,
inner: Arc<Inner>,
}
pub struct WakerSpawner<T: 'static>(Wrapper<false, Handler<T>, Sender, usize>);

pub struct Waker<T: 'static>(Wrapper<false, Handler<T>, Sender, usize>);

struct Handler<T> {
value: T,
Expand All @@ -18,16 +17,7 @@ struct Handler<T> {
#[derive(Clone)]
struct Sender(Arc<Inner>);

impl Drop for Sender {
fn drop(&mut self) {
if Arc::strong_count(&self.0) == 1 {
self.0.closed.store(true, Ordering::Relaxed);
self.0.waker.wake();
}
}
}

impl<T> Waker<T> {
impl<T> WakerSpawner<T> {
#[track_caller]
pub fn new(value: T, handler: fn(&T, usize)) -> Option<Self> {
let inner = Arc::new(Inner {
Expand Down Expand Up @@ -91,20 +81,32 @@ impl<T> Waker<T> {
},
)?;

Some(Self { wrapper, inner })
Some(Self(wrapper))
}

pub fn waker(&self) -> Waker<T> {
Waker(self.0.clone())
}
}

impl<T> Drop for WakerSpawner<T> {
fn drop(&mut self) {
self.0.with_sender(|inner| {
inner.0.closed.store(true, Ordering::Relaxed);
inner.0.waker.wake();
});
}
}

impl<T> Waker<T> {
pub fn wake(&self) {
self.wrapper.send(1)
self.0.send(1)
}
}

impl<T> Clone for Waker<T> {
fn clone(&self) -> Self {
Self {
wrapper: self.wrapper.clone(),
inner: Arc::clone(&self.inner),
}
Self(self.0.clone())
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/platform_impl/web/async/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ impl<const SYNC: bool, V, S: Clone + Send, E> Wrapper<SYNC, V, S, E> {
}
})
}

pub fn with_sender<T>(&self, f: impl FnOnce(&S) -> T) -> Option<T> {
Self::MAIN_THREAD.with(|is_main_thread| {
if *is_main_thread.deref() {
Some(f(&self.sender_data))
} else {
None
}
})
}
}

impl<const SYNC: bool, V, S: Clone + Send, E> Clone for Wrapper<SYNC, V, S, E> {
Expand Down
19 changes: 14 additions & 5 deletions src/platform_impl/web/event_loop/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use std::iter;
use std::marker::PhantomData;
use std::sync::mpsc::{self, Receiver, Sender};

use crate::error::EventLoopError;
use crate::event::Event;
use crate::event_loop::{ControlFlow, EventLoopWindowTarget as RootEventLoopWindowTarget};

use super::r#async::WakerSpawner;
use super::{backend, device, window};

mod proxy;
Expand All @@ -17,6 +19,7 @@ pub use window_target::EventLoopWindowTarget;

pub struct EventLoop<T: 'static> {
elw: RootEventLoopWindowTarget<T>,
proxy_spawner: WakerSpawner<runner::Shared>,
user_event_sender: Sender<T>,
user_event_receiver: Receiver<T>,
}
Expand All @@ -27,11 +30,17 @@ pub(crate) struct PlatformSpecificEventLoopAttributes {}
impl<T> EventLoop<T> {
pub(crate) fn new(_: &PlatformSpecificEventLoopAttributes) -> Result<Self, EventLoopError> {
let (user_event_sender, user_event_receiver) = mpsc::channel();
let elw = RootEventLoopWindowTarget {
p: EventLoopWindowTarget::new(),
_marker: PhantomData,
};
let proxy_spawner = WakerSpawner::new(elw.p.runner.clone(), |runner, count| {
runner.send_events(iter::repeat(Event::UserEvent(())).take(count))
})
.expect("`EventLoop` has to be created in the main thread");
Ok(EventLoop {
elw: RootEventLoopWindowTarget {
p: EventLoopWindowTarget::new(),
_marker: PhantomData,
},
elw,
proxy_spawner,
user_event_sender,
user_event_receiver,
})
Expand Down Expand Up @@ -101,7 +110,7 @@ impl<T> EventLoop<T> {
}

pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy::new(self.elw.p.runner.clone(), self.user_event_sender.clone())
EventLoopProxy::new(self.proxy_spawner.waker(), self.user_event_sender.clone())
}

pub fn window_target(&self) -> &RootEventLoopWindowTarget<T> {
Expand Down
12 changes: 2 additions & 10 deletions src/platform_impl/web/event_loop/proxy.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use std::iter;
use std::sync::mpsc::Sender;

use super::runner;
use crate::event::Event;
use crate::event_loop::EventLoopClosed;
use crate::platform_impl::platform::r#async::Waker;

Expand All @@ -12,14 +10,8 @@ pub struct EventLoopProxy<T: 'static> {
}

impl<T: 'static> EventLoopProxy<T> {
pub fn new(runner: runner::Shared, sender: Sender<T>) -> Self {
Self {
runner: Waker::new(runner, |runner, count| {
runner.send_events(iter::repeat(Event::UserEvent(())).take(count))
})
.unwrap(),
sender,
}
pub fn new(runner: Waker<runner::Shared>, sender: Sender<T>) -> Self {
Self { runner, sender }
}

pub fn send_event(&self, event: T) -> Result<(), EventLoopClosed<T>> {
Expand Down

0 comments on commit eacf2a4

Please sign in to comment.