api: make EventLoopProxy wrap an opaque type
The proxy is intended to be Clone, thus use `Arc` for it internally and don't require backends for it to be `Clone`. Use `EventLoopProxyProvider` to hide the backend's proxy implementation details. Co-authored-by: daxpedda <daxpedda@gmail.com>
This commit is contained in:
parent
ae4c449670
commit
3a60cbaba5
24 changed files with 256 additions and 307 deletions
|
|
@ -6,15 +6,13 @@ mod channel;
|
|||
mod concurrent_queue;
|
||||
mod dispatcher;
|
||||
mod notifier;
|
||||
mod waker;
|
||||
mod wrapper;
|
||||
|
||||
use atomic_waker::AtomicWaker;
|
||||
pub(crate) use atomic_waker::AtomicWaker;
|
||||
use concurrent_queue::{ConcurrentQueue, PushError};
|
||||
|
||||
pub use self::abortable::{AbortHandle, Abortable, DropAbortHandle};
|
||||
pub use self::channel::{channel, Receiver, Sender};
|
||||
pub use self::dispatcher::{DispatchRunner, Dispatcher};
|
||||
pub use self::notifier::{Notified, Notifier};
|
||||
pub use self::waker::{Waker, WakerSpawner};
|
||||
use self::wrapper::Wrapper;
|
||||
pub(crate) use self::wrapper::Wrapper;
|
||||
|
|
|
|||
|
|
@ -1,117 +0,0 @@
|
|||
use std::future;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use super::{AtomicWaker, Wrapper};
|
||||
|
||||
pub struct WakerSpawner<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||
|
||||
pub struct Waker<T: 'static>(Wrapper<Handler<T>, Sender, ()>);
|
||||
|
||||
struct Handler<T> {
|
||||
value: T,
|
||||
handler: fn(&T, bool),
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct Sender(Arc<Inner>);
|
||||
|
||||
impl<T> WakerSpawner<T> {
|
||||
pub fn new(main_thread: MainThreadMarker, value: T, handler: fn(&T, bool)) -> Self {
|
||||
let inner = Arc::new(Inner {
|
||||
awoken: AtomicBool::new(false),
|
||||
waker: AtomicWaker::new(),
|
||||
closed: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
let handler = Handler { value, handler };
|
||||
|
||||
let sender = Sender(Arc::clone(&inner));
|
||||
|
||||
Self(Wrapper::new(
|
||||
main_thread,
|
||||
handler,
|
||||
|handler, _| {
|
||||
let handler = handler.borrow();
|
||||
let handler = handler.as_ref().unwrap();
|
||||
(handler.handler)(&handler.value, true);
|
||||
},
|
||||
{
|
||||
let inner = Arc::clone(&inner);
|
||||
|
||||
move |handler| async move {
|
||||
while future::poll_fn(|cx| {
|
||||
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
inner.waker.register(cx.waker());
|
||||
|
||||
if inner.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
if inner.closed.load(Ordering::Relaxed) {
|
||||
return Poll::Ready(false);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
let handler = handler.borrow();
|
||||
let handler = handler.as_ref().unwrap();
|
||||
(handler.handler)(&handler.value, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
sender,
|
||||
|inner, _| {
|
||||
inner.0.awoken.store(true, Ordering::Relaxed);
|
||||
inner.0.waker.wake();
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn waker(&self) -> Waker<T> {
|
||||
Waker(self.0.clone())
|
||||
}
|
||||
|
||||
pub fn take(&self) -> bool {
|
||||
debug_assert!(
|
||||
MainThreadMarker::new().is_some(),
|
||||
"this should only be called from the main thread"
|
||||
);
|
||||
|
||||
self.0.with_sender_data(|inner| inner.0.awoken.swap(false, Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for WakerSpawner<T> {
|
||||
fn drop(&mut self) {
|
||||
self.0.with_sender_data(|inner| {
|
||||
inner.0.closed.store(true, Ordering::Relaxed);
|
||||
inner.0.waker.wake();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Waker<T> {
|
||||
pub fn wake(&self) {
|
||||
self.0.send(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for Waker<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
struct Inner {
|
||||
awoken: AtomicBool,
|
||||
waker: AtomicWaker,
|
||||
closed: AtomicBool,
|
||||
}
|
||||
|
|
@ -10,7 +10,6 @@ pub(crate) mod runner;
|
|||
mod state;
|
||||
mod window_target;
|
||||
|
||||
pub(crate) use proxy::EventLoopProxy;
|
||||
pub(crate) use window_target::{ActiveEventLoop, OwnedDisplayHandle};
|
||||
|
||||
pub struct EventLoop {
|
||||
|
|
|
|||
|
|
@ -1,17 +1,101 @@
|
|||
use super::runner::WeakShared;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
use std::future;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::task::Poll;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EventLoopProxy {
|
||||
runner: Waker<WeakShared>,
|
||||
use super::super::main_thread::MainThreadMarker;
|
||||
use crate::event_loop::EventLoopProxyProvider;
|
||||
use crate::platform_impl::web::event_loop::runner::WeakShared;
|
||||
use crate::platform_impl::web::r#async::{AtomicWaker, Wrapper};
|
||||
|
||||
pub struct EventLoopProxy(Wrapper<WeakShared, Arc<State>, ()>);
|
||||
|
||||
struct State {
|
||||
awoken: AtomicBool,
|
||||
waker: AtomicWaker,
|
||||
closed: AtomicBool,
|
||||
}
|
||||
|
||||
impl EventLoopProxy {
|
||||
pub fn new(runner: Waker<WeakShared>) -> Self {
|
||||
Self { runner }
|
||||
pub fn new(main_thread: MainThreadMarker, runner: WeakShared) -> Self {
|
||||
let state = Arc::new(State {
|
||||
awoken: AtomicBool::new(false),
|
||||
waker: AtomicWaker::new(),
|
||||
closed: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
Self(Wrapper::new(
|
||||
main_thread,
|
||||
runner,
|
||||
|runner, _| {
|
||||
let runner = runner.borrow();
|
||||
let runner = runner.as_ref().unwrap();
|
||||
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(true);
|
||||
}
|
||||
},
|
||||
{
|
||||
let state = Arc::clone(&state);
|
||||
|
||||
move |runner| async move {
|
||||
while future::poll_fn(|cx| {
|
||||
if state.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
state.waker.register(cx.waker());
|
||||
|
||||
if state.awoken.swap(false, Ordering::Relaxed) {
|
||||
Poll::Ready(true)
|
||||
} else {
|
||||
if state.closed.load(Ordering::Relaxed) {
|
||||
return Poll::Ready(false);
|
||||
}
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
})
|
||||
.await
|
||||
{
|
||||
let runner = runner.borrow();
|
||||
let runner = runner.as_ref().unwrap();
|
||||
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
state,
|
||||
|state, _| {
|
||||
state.awoken.store(true, Ordering::Relaxed);
|
||||
state.waker.wake();
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
pub fn wake_up(&self) {
|
||||
self.runner.wake();
|
||||
pub fn take(&self) -> bool {
|
||||
debug_assert!(
|
||||
MainThreadMarker::new().is_some(),
|
||||
"this should only be called from the main thread"
|
||||
);
|
||||
|
||||
self.0.with_sender_data(|state| state.awoken.swap(false, Ordering::Relaxed))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for EventLoopProxy {
|
||||
fn drop(&mut self) {
|
||||
self.0.with_sender_data(|state| {
|
||||
state.closed.store(true, Ordering::Relaxed);
|
||||
state.waker.wake();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl EventLoopProxyProvider for EventLoopProxy {
|
||||
fn wake_up(&self) {
|
||||
self.0.send(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::collections::{HashSet, VecDeque};
|
|||
use std::iter;
|
||||
use std::ops::Deref;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::sync::Arc;
|
||||
|
||||
use wasm_bindgen::prelude::Closure;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
|
@ -13,13 +14,14 @@ use super::super::event;
|
|||
use super::super::main_thread::MainThreadMarker;
|
||||
use super::super::monitor::MonitorHandler;
|
||||
use super::backend;
|
||||
use super::proxy::EventLoopProxy;
|
||||
use super::state::State;
|
||||
use crate::dpi::PhysicalSize;
|
||||
use crate::event::{DeviceEvent, ElementState, Event, RawKeyEvent, StartCause, WindowEvent};
|
||||
use crate::event_loop::{ControlFlow, DeviceEvents};
|
||||
use crate::platform::web::{PollStrategy, WaitUntilStrategy};
|
||||
use crate::platform_impl::platform::backend::EventListenerHandle;
|
||||
use crate::platform_impl::platform::r#async::{DispatchRunner, Waker, WakerSpawner};
|
||||
use crate::platform_impl::platform::r#async::DispatchRunner;
|
||||
use crate::platform_impl::platform::window::Inner;
|
||||
use crate::window::WindowId;
|
||||
|
||||
|
|
@ -37,7 +39,7 @@ type OnEventHandle<T> = RefCell<Option<EventListenerHandle<dyn FnMut(T)>>>;
|
|||
|
||||
struct Execution {
|
||||
main_thread: MainThreadMarker,
|
||||
proxy_spawner: WakerSpawner<WeakShared>,
|
||||
event_loop_proxy: Arc<EventLoopProxy>,
|
||||
control_flow: Cell<ControlFlow>,
|
||||
poll_strategy: Cell<PollStrategy>,
|
||||
wait_until_strategy: Cell<WaitUntilStrategy>,
|
||||
|
|
@ -140,12 +142,7 @@ impl Shared {
|
|||
let document = window.document().expect("Failed to obtain document");
|
||||
|
||||
Shared(Rc::<Execution>::new_cyclic(|weak| {
|
||||
let proxy_spawner =
|
||||
WakerSpawner::new(main_thread, WeakShared(weak.clone()), |runner, local| {
|
||||
if let Some(runner) = runner.upgrade() {
|
||||
runner.send_proxy_wake_up(local);
|
||||
}
|
||||
});
|
||||
let proxy_spawner = EventLoopProxy::new(main_thread, WeakShared(weak.clone()));
|
||||
|
||||
let monitor = MonitorHandler::new(
|
||||
main_thread,
|
||||
|
|
@ -156,7 +153,7 @@ impl Shared {
|
|||
|
||||
Execution {
|
||||
main_thread,
|
||||
proxy_spawner,
|
||||
event_loop_proxy: Arc::new(proxy_spawner),
|
||||
control_flow: Cell::new(ControlFlow::default()),
|
||||
poll_strategy: Cell::new(PollStrategy::default()),
|
||||
wait_until_strategy: Cell::new(WaitUntilStrategy::default()),
|
||||
|
|
@ -653,7 +650,7 @@ impl Shared {
|
|||
// Pre-fetch `UserEvent`s to avoid having to wait until the next event loop cycle.
|
||||
events.extend(
|
||||
self.0
|
||||
.proxy_spawner
|
||||
.event_loop_proxy
|
||||
.take()
|
||||
.then_some(Event::UserWakeUp)
|
||||
.map(EventWrapper::from),
|
||||
|
|
@ -818,8 +815,8 @@ impl Shared {
|
|||
self.0.wait_until_strategy.get()
|
||||
}
|
||||
|
||||
pub(crate) fn waker(&self) -> Waker<WeakShared> {
|
||||
self.0.proxy_spawner.waker()
|
||||
pub(crate) fn event_loop_proxy(&self) -> &Arc<EventLoopProxy> {
|
||||
&self.0.event_loop_proxy
|
||||
}
|
||||
|
||||
pub(crate) fn weak(&self) -> WeakShared {
|
||||
|
|
|
|||
|
|
@ -2,13 +2,14 @@ use std::cell::Cell;
|
|||
use std::clone::Clone;
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use web_sys::Element;
|
||||
|
||||
use super::super::monitor::MonitorPermissionFuture;
|
||||
use super::super::{lock, KeyEventExtra};
|
||||
use super::runner::{EventWrapper, WeakShared};
|
||||
use super::{backend, runner, EventLoopProxy};
|
||||
use super::runner::EventWrapper;
|
||||
use super::{backend, runner};
|
||||
use crate::error::{NotSupportedError, RequestError};
|
||||
use crate::event::{ElementState, Event, KeyEvent, TouchPhase, WindowEvent};
|
||||
use crate::event_loop::{
|
||||
|
|
@ -19,7 +20,7 @@ use crate::keyboard::ModifiersState;
|
|||
use crate::monitor::MonitorHandle as RootMonitorHandle;
|
||||
use crate::platform::web::{CustomCursorFuture, PollStrategy, WaitUntilStrategy};
|
||||
use crate::platform_impl::platform::cursor::CustomCursor;
|
||||
use crate::platform_impl::platform::r#async::Waker;
|
||||
use crate::platform_impl::web::event_loop::proxy::EventLoopProxy;
|
||||
use crate::platform_impl::Window;
|
||||
use crate::window::{CustomCursor as RootCustomCursor, CustomCursorSource, Theme, WindowId};
|
||||
|
||||
|
|
@ -476,15 +477,15 @@ impl ActiveEventLoop {
|
|||
self.runner.monitor().has_detailed_monitor_permission()
|
||||
}
|
||||
|
||||
pub(crate) fn waker(&self) -> Waker<WeakShared> {
|
||||
self.runner.waker()
|
||||
pub(crate) fn event_loop_proxy(&self) -> Arc<EventLoopProxy> {
|
||||
self.runner.event_loop_proxy().clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl RootActiveEventLoop for ActiveEventLoop {
|
||||
fn create_proxy(&self) -> RootEventLoopProxy {
|
||||
let event_loop_proxy = EventLoopProxy::new(self.waker());
|
||||
RootEventLoopProxy { event_loop_proxy }
|
||||
let event_loop_proxy = self.event_loop_proxy();
|
||||
RootEventLoopProxy::new(event_loop_proxy)
|
||||
}
|
||||
|
||||
fn create_window(
|
||||
|
|
|
|||
|
|
@ -38,8 +38,7 @@ pub(crate) use cursor::{
|
|||
};
|
||||
|
||||
pub(crate) use self::event_loop::{
|
||||
ActiveEventLoop, EventLoop, EventLoopProxy, OwnedDisplayHandle,
|
||||
PlatformSpecificEventLoopAttributes,
|
||||
ActiveEventLoop, EventLoop, OwnedDisplayHandle, PlatformSpecificEventLoopAttributes,
|
||||
};
|
||||
pub(crate) use self::keyboard::KeyEventExtra;
|
||||
pub(crate) use self::monitor::{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue