Make EventLoopProxy Sync

Co-authored-by: daxpedda <daxpedda@gmail.com>
Closes: #3448
This commit is contained in:
Mads Marquart 2024-02-01 14:27:44 +01:00 committed by Kirill Chibisov
parent e61a7320a2
commit 31f8b816bd
9 changed files with 26 additions and 13 deletions

View file

@ -14,6 +14,7 @@ Unreleased` header.
- On X11, don't require XIM to run. - On X11, don't require XIM to run.
- On X11, fix xkb state not being updated correctly sometimes leading to wrong input. - On X11, fix xkb state not being updated correctly sometimes leading to wrong input.
- Fix compatibility with 32-bit platforms without 64-bit atomics. - Fix compatibility with 32-bit platforms without 64-bit atomics.
- Implement `Sync` for `EventLoopProxy<T: Send>`.
- On X11, fix swapped instance and general class names. - On X11, fix swapped instance and general class names.
- **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`. - **Breaking:** Removed unnecessary generic parameter `T` from `EventLoopWindowTarget`.
- On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example. - On Windows, macOS, X11, Wayland and Web, implement setting images as cursors. See the `custom_cursors.rs` example.

View file

@ -253,7 +253,8 @@ impl<T> EventLoop<T> {
self.event_loop.run(event_handler) self.event_loop.run(event_handler)
} }
/// Creates an [`EventLoopProxy`] that can be used to dispatch user events to the main event loop. /// Creates an [`EventLoopProxy`] that can be used to dispatch user events
/// to the main event loop, possibly from another thread.
pub fn create_proxy(&self) -> EventLoopProxy<T> { pub fn create_proxy(&self) -> EventLoopProxy<T> {
EventLoopProxy { EventLoopProxy {
event_loop_proxy: self.event_loop.create_proxy(), event_loop_proxy: self.event_loop.create_proxy(),

View file

@ -229,6 +229,7 @@ pub struct EventLoopProxy<T> {
} }
unsafe impl<T: Send> Send for EventLoopProxy<T> {} unsafe impl<T: Send> Send for EventLoopProxy<T> {}
unsafe impl<T: Send> Sync for EventLoopProxy<T> {}
impl<T> Clone for EventLoopProxy<T> { impl<T> Clone for EventLoopProxy<T> {
fn clone(&self) -> EventLoopProxy<T> { fn clone(&self) -> EventLoopProxy<T> {

View file

@ -532,6 +532,7 @@ pub struct EventLoopProxy<T> {
} }
unsafe impl<T: Send> Send for EventLoopProxy<T> {} unsafe impl<T: Send> Send for EventLoopProxy<T> {}
unsafe impl<T: Send> Sync for EventLoopProxy<T> {}
impl<T> Drop for EventLoopProxy<T> { impl<T> Drop for EventLoopProxy<T> {
fn drop(&mut self) { fn drop(&mut self) {

View file

@ -5,7 +5,7 @@ use std::{
sync::{Arc, Condvar, Mutex}, sync::{Arc, Condvar, Mutex},
}; };
pub struct Dispatcher<T: 'static>(Wrapper<true, T, Sender<Closure<T>>, Closure<T>>); pub struct Dispatcher<T: 'static>(Wrapper<T, Sender<Closure<T>>, Closure<T>>);
struct Closure<T>(Box<dyn FnOnce(&T) + Send>); struct Closure<T>(Box<dyn FnOnce(&T) + Send>);
@ -85,7 +85,7 @@ impl<T> Dispatcher<T> {
} }
pub struct DispatchRunner<T: 'static> { pub struct DispatchRunner<T: 'static> {
wrapper: Wrapper<true, T, Sender<Closure<T>>, Closure<T>>, wrapper: Wrapper<T, Sender<Closure<T>>, Closure<T>>,
receiver: Receiver<Closure<T>>, receiver: Receiver<Closure<T>>,
} }

View file

@ -6,9 +6,9 @@ use std::task::Poll;
use super::super::main_thread::MainThreadMarker; use super::super::main_thread::MainThreadMarker;
use super::{AtomicWaker, Wrapper}; use super::{AtomicWaker, Wrapper};
pub struct WakerSpawner<T: 'static>(Wrapper<false, Handler<T>, Sender, usize>); pub struct WakerSpawner<T: 'static>(Wrapper<Handler<T>, Sender, usize>);
pub struct Waker<T: 'static>(Wrapper<false, Handler<T>, Sender, usize>); pub struct Waker<T: 'static>(Wrapper<Handler<T>, Sender, usize>);
struct Handler<T> { struct Handler<T> {
value: T, value: T,

View file

@ -6,14 +6,14 @@ use std::sync::Arc;
// Unsafe wrapper type that allows us to use `T` when it's not `Send` from other threads. // 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. // `value` **must** only be accessed on the main thread.
pub struct Wrapper<const SYNC: bool, V: 'static, S: Clone + Send, E> { pub struct Wrapper<V: 'static, S: Clone + Send, E> {
value: Value<SYNC, V>, value: Value<V>,
handler: fn(&RefCell<Option<V>>, E), handler: fn(&RefCell<Option<V>>, E),
sender_data: S, sender_data: S,
sender_handler: fn(&S, E), sender_handler: fn(&S, E),
} }
struct Value<const SYNC: bool, V> { struct Value<V> {
// SAFETY: // SAFETY:
// This value must not be accessed if not on the main thread. // This value must not be accessed if not on the main thread.
// //
@ -28,11 +28,11 @@ struct Value<const SYNC: bool, V> {
} }
// SAFETY: See `Self::value`. // SAFETY: See `Self::value`.
unsafe impl<const SYNC: bool, V> Send for Value<SYNC, V> {} unsafe impl<V> Send for Value<V> {}
// SAFETY: See `Self::value`. // SAFETY: See `Self::value`.
unsafe impl<V> Sync for Value<true, V> {} unsafe impl<V> Sync for Value<V> {}
impl<const SYNC: bool, V, S: Clone + Send, E> Wrapper<SYNC, V, S, E> { impl<V, S: Clone + Send, E> Wrapper<V, S, E> {
#[track_caller] #[track_caller]
pub fn new<R: Future<Output = ()>>( pub fn new<R: Future<Output = ()>>(
_: MainThreadMarker, _: MainThreadMarker,
@ -81,7 +81,7 @@ impl<const SYNC: bool, V, S: Clone + Send, E> Wrapper<SYNC, V, S, E> {
} }
} }
impl<const SYNC: bool, V, S: Clone + Send, E> Clone for Wrapper<SYNC, V, S, E> { impl<V, S: Clone + Send, E> Clone for Wrapper<V, S, E> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
value: Value { value: Value {

View file

@ -5,7 +5,7 @@ fn needs_send<T: Send>() {}
fn event_loop_proxy_send() { fn event_loop_proxy_send() {
#[allow(dead_code)] #[allow(dead_code)]
fn is_send<T: 'static + Send>() { fn is_send<T: 'static + Send>() {
// ensures that `winit::EventLoopProxy` implements `Send` // ensures that `winit::EventLoopProxy<T: Send>` implements `Send`
needs_send::<winit::event_loop::EventLoopProxy<T>>(); needs_send::<winit::event_loop::EventLoopProxy<T>>();
} }
} }

View file

@ -1,6 +1,15 @@
#[allow(dead_code)] #[allow(dead_code)]
fn needs_sync<T: Sync>() {} fn needs_sync<T: Sync>() {}
#[test]
fn event_loop_proxy_send() {
#[allow(dead_code)]
fn is_send<T: 'static + Send>() {
// ensures that `winit::EventLoopProxy<T: Send>` implements `Sync`
needs_sync::<winit::event_loop::EventLoopProxy<T>>();
}
}
#[test] #[test]
fn window_sync() { fn window_sync() {
// ensures that `winit::Window` implements `Sync` // ensures that `winit::Window` implements `Sync`