Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make handles Send + Sync #152

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub struct AndroidNdkWindowHandle {
pub a_native_window: NonNull<c_void>,
}

// SAFETY: `ndk::native_window::NativeWindow` is `Send + Sync`.
unsafe impl Send for AndroidNdkWindowHandle {}
unsafe impl Sync for AndroidNdkWindowHandle {}

impl AndroidNdkWindowHandle {
/// Create a new handle to an `ANativeWindow`.
///
Expand Down
14 changes: 14 additions & 0 deletions src/appkit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,27 @@ impl AppKitDisplayHandle {
}

/// Raw window handle for AppKit.
///
/// Note that while this is `Send + Sync`, it is only usable from the main
/// thread. Any usage of `NSView` outside the main thread may be undefined
/// behaviour, unless explicitly documented otherwise.
///
/// You must check whether the thread is the main thread before accessing
/// this, and if it is not, you should execute your code to access the view
/// on the main thread instead using `libdispatch`.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AppKitWindowHandle {
/// A pointer to an `NSView` object.
pub ns_view: NonNull<c_void>,
}

// SAFETY: Only accessible from the main thread.
//
// Acts as-if the view is wrapped in `MainThreadBound<T>`.
unsafe impl Send for AppKitWindowHandle {}
unsafe impl Sync for AppKitWindowHandle {}

impl AppKitWindowHandle {
/// Create a new handle to a view.
///
Expand Down
12 changes: 2 additions & 10 deletions src/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ impl<H: HasDisplayHandle + ?Sized> HasDisplayHandle for alloc::sync::Arc<H> {
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct DisplayHandle<'a> {
raw: RawDisplayHandle,
_marker: PhantomData<&'a *const ()>,
_marker: PhantomData<&'a ()>,
}

impl fmt::Debug for DisplayHandle<'_> {
Expand Down Expand Up @@ -210,7 +210,7 @@ impl<H: HasWindowHandle + ?Sized> HasWindowHandle for alloc::sync::Arc<H> {
#[derive(PartialEq, Eq, Hash, Copy, Clone)]
pub struct WindowHandle<'a> {
raw: RawWindowHandle,
_marker: PhantomData<&'a *const ()>,
_marker: PhantomData<&'a ()>,
}

impl fmt::Debug for WindowHandle<'_> {
Expand Down Expand Up @@ -280,11 +280,3 @@ impl HasWindowHandle for WindowHandle<'_> {
Ok(*self)
}
}

/// ```compile_fail
/// use raw_window_handle::{DisplayHandle, WindowHandle};
/// fn _assert<T: Send + Sync>() {}
/// _assert::<DisplayHandle<'static>>();
/// _assert::<WindowHandle<'static>>();
/// ```
fn _not_send_or_sync() {}
6 changes: 6 additions & 0 deletions src/haiku.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ pub struct HaikuWindowHandle {
pub b_direct_window: Option<NonNull<c_void>>,
}

// SAFETY: `BWindow` and `BDirectWindow` are thread safe.
//
// TODO: Documentation for this.
unsafe impl Send for HaikuWindowHandle {}
unsafe impl Sync for HaikuWindowHandle {}

impl HaikuWindowHandle {
/// Create a new handle to a window.
///
Expand Down
41 changes: 41 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,3 +420,44 @@ from_impl!(
);
from_impl!(RawWindowHandle, AndroidNdk, AndroidNdkWindowHandle);
from_impl!(RawWindowHandle, Haiku, HaikuWindowHandle);

#[cfg(test)]
mod tests {
use core::panic::{RefUnwindSafe, UnwindSafe};

use super::*;

#[test]
fn auto_traits() {
fn assert_send_sync<T: Send + Sync>() {}
fn assert_unwindsafe<T: UnwindSafe + RefUnwindSafe>() {}
fn assert_unpin<T: Unpin>() {}

assert_send_sync::<RawDisplayHandle>();
assert_send_sync::<DisplayHandle<'_>>();
assert_unwindsafe::<RawDisplayHandle>();
assert_unwindsafe::<DisplayHandle<'_>>();
assert_unpin::<RawDisplayHandle>();
assert_unpin::<DisplayHandle<'_>>();

assert_send_sync::<RawWindowHandle>();
assert_send_sync::<WindowHandle<'_>>();
assert_unwindsafe::<RawWindowHandle>();
assert_unwindsafe::<WindowHandle<'_>>();
assert_unpin::<RawWindowHandle>();
assert_unpin::<WindowHandle<'_>>();

assert_send_sync::<HandleError>();
assert_unwindsafe::<HandleError>();
assert_unpin::<HandleError>();
}

#[allow(deprecated, unused)]
fn assert_object_safe(
_: &dyn HasRawWindowHandle,
_: &dyn HasRawDisplayHandle,
_: &dyn HasWindowHandle,
_: &dyn HasDisplayHandle,
) {
}
}
7 changes: 7 additions & 0 deletions src/redox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ pub struct OrbitalWindowHandle {
pub window: NonNull<c_void>,
}

// SAFETY: `orbclient`` windows are essentially just a file descriptor, and
// are hence thread safe.
//
// TODO: Documentation for this.
unsafe impl Send for OrbitalWindowHandle {}
unsafe impl Sync for OrbitalWindowHandle {}

impl OrbitalWindowHandle {
/// Create a new handle to a window.
///
Expand Down
15 changes: 15 additions & 0 deletions src/uikit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ impl UiKitDisplayHandle {
}

/// Raw window handle for UIKit.
///
/// Note that while this is `Send + Sync`, it is only usable from the main
/// thread. Any usage of `UIView` and `UIViewController` outside the main
/// thread may be undefined behaviour, unless explicitly documented
/// otherwise.
///
/// You must check whether the thread is the main thread before accessing
/// this, and if it is not, you should execute your code to access the view
/// and view controller on the main thread instead using `libdispatch`.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct UiKitWindowHandle {
Expand All @@ -31,6 +40,12 @@ pub struct UiKitWindowHandle {
pub ui_view_controller: Option<NonNull<c_void>>,
}

// SAFETY: Only accessible from the main thread.
//
// Acts as-if the view is wrapped in `MainThreadBound<T>`.
unsafe impl Send for UiKitWindowHandle {}
unsafe impl Sync for UiKitWindowHandle {}

impl UiKitWindowHandle {
/// Create a new handle to a view.
///
Expand Down
36 changes: 36 additions & 0 deletions src/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ pub struct XlibDisplayHandle {
pub screen: c_int,
}

// SAFETY: Xlib `Display` is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for XlibDisplayHandle {}
unsafe impl Sync for XlibDisplayHandle {}

impl XlibDisplayHandle {
/// Create a new handle to a display.
///
Expand Down Expand Up @@ -94,6 +100,12 @@ pub struct XcbDisplayHandle {
pub screen: c_int,
}

// SAFETY: `xcb_connection_t` is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for XcbDisplayHandle {}
unsafe impl Sync for XcbDisplayHandle {}

impl XcbDisplayHandle {
/// Create a new handle to a connection and screen.
///
Expand Down Expand Up @@ -158,6 +170,12 @@ pub struct WaylandDisplayHandle {
pub display: NonNull<c_void>,
}

// SAFETY: `wl_display` is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for WaylandDisplayHandle {}
unsafe impl Sync for WaylandDisplayHandle {}

impl WaylandDisplayHandle {
/// Create a new display handle.
///
Expand Down Expand Up @@ -186,6 +204,12 @@ pub struct WaylandWindowHandle {
pub surface: NonNull<c_void>,
}

// SAFETY: `wl_surface` is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for WaylandWindowHandle {}
unsafe impl Sync for WaylandWindowHandle {}

impl WaylandWindowHandle {
/// Create a new handle to a surface.
///
Expand Down Expand Up @@ -267,6 +291,12 @@ pub struct GbmDisplayHandle {
pub gbm_device: NonNull<c_void>,
}

// SAFETY: GBM is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for GbmDisplayHandle {}
unsafe impl Sync for GbmDisplayHandle {}

impl GbmDisplayHandle {
/// Create a new handle to a device.
///
Expand Down Expand Up @@ -295,6 +325,12 @@ pub struct GbmWindowHandle {
pub gbm_surface: NonNull<c_void>,
}

// SAFETY: GBM is thread safe.
//
// TODO: Documentation for this?
unsafe impl Send for GbmWindowHandle {}
unsafe impl Sync for GbmWindowHandle {}

impl GbmWindowHandle {
/// Create a new handle to a surface.
///
Expand Down
16 changes: 16 additions & 0 deletions src/web.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ pub struct WebCanvasWindowHandle {
pub obj: NonNull<c_void>,
}

// SAFETY: Only accessible from the main thread.
unsafe impl Send for WebCanvasWindowHandle {}
unsafe impl Sync for WebCanvasWindowHandle {}

impl WebCanvasWindowHandle {
/// Create a new handle from a pointer to [`HtmlCanvasElement`].
///
Expand Down Expand Up @@ -121,6 +125,8 @@ impl WebCanvasWindowHandle {
///
/// The inner pointer must be valid. This is ensured if this handle was
/// borrowed from [`WindowHandle`][crate::WindowHandle].
///
/// Additionally, the current thread must be the main thread.
pub unsafe fn as_wasm_bindgen_0_2(&self) -> &wasm_bindgen::JsValue {
unsafe { self.obj.cast().as_ref() }
}
Expand All @@ -130,6 +136,10 @@ impl WebCanvasWindowHandle {
/// [`wasm-bindgen`].
///
/// [`wasm-bindgen`]: https://crates.io/crates/wasm-bindgen
///
/// Note that while this is `Send + Sync`, it is only usable from the main
/// thread. Any usage of `JsValue` outside the main thread is undefined
/// behaviour.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WebOffscreenCanvasWindowHandle {
Expand All @@ -145,6 +155,10 @@ pub struct WebOffscreenCanvasWindowHandle {
pub obj: NonNull<c_void>,
}

// SAFETY: Only accessible from the main thread.
unsafe impl Send for WebOffscreenCanvasWindowHandle {}
unsafe impl Sync for WebOffscreenCanvasWindowHandle {}

impl WebOffscreenCanvasWindowHandle {
/// Create a new handle from a pointer to an [`OffscreenCanvas`].
///
Expand Down Expand Up @@ -191,6 +205,8 @@ impl WebOffscreenCanvasWindowHandle {
///
/// The inner pointer must be valid. This is ensured if this handle was
/// borrowed from [`WindowHandle`][crate::WindowHandle].
///
/// Additionally, the current thread must be the main thread.
pub unsafe fn as_wasm_bindgen_0_2(&self) -> &wasm_bindgen::JsValue {
unsafe { self.obj.cast().as_ref() }
}
Expand Down
7 changes: 7 additions & 0 deletions src/windows.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,20 @@ impl Win32WindowHandle {
}

/// Raw window handle for WinRT.
///
/// This handle is `Send + Sync`, but it is unknown whether that is actually
/// sound.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct WinRtWindowHandle {
/// A WinRT `CoreWindow` handle.
pub core_window: NonNull<c_void>,
}

// SAFETY: Unknown.
unsafe impl Send for WinRtWindowHandle {}
unsafe impl Sync for WinRtWindowHandle {}

impl WinRtWindowHandle {
/// Create a new handle to a window.
///
Expand Down