diff --git a/crates/bevy_window/src/raw_window_handle.rs b/crates/bevy_window/src/raw_window_handle.rs index 76f1411261c80..5bc122558d78f 100644 --- a/crates/bevy_window/src/raw_window_handle.rs +++ b/crates/bevy_window/src/raw_window_handle.rs @@ -1,7 +1,10 @@ use raw_window_handle::{HasRawWindowHandle, RawWindowHandle}; -/// This wrapper exist to enable safely passing a [`RawWindowHandle`] across threads. Extracting the handle -/// is still an unsafe operation, so the caller must still validate that using the raw handle is safe for a given context. +/// A wrapper over [`RawWindowHandle`] that allows us to safely pass it across threads. +/// +/// Depending on the platform, the underlying pointer-containing handle cannot be used on all threads, +/// and so we cannot simply make it (or any type that has a safe operation to get a [`RawWindowHandle`]) +/// thread-safe. #[derive(Debug, Clone)] pub struct RawWindowHandleWrapper(RawWindowHandle); @@ -10,12 +13,14 @@ impl RawWindowHandleWrapper { Self(handle) } + /// Returns a [`HasRawWindowHandle`] impl, which exposes [`RawWindowHandle`]. + /// /// # Safety - /// This returns a [`HasRawWindowHandle`] impl, which exposes [`RawWindowHandle`]. Some platforms - /// have constraints on where/how this handle can be used. For example, some platforms don't support doing window + /// + /// Some platforms have constraints on where/how this handle can be used. For example, some platforms don't support doing window /// operations off of the main thread. The caller must ensure the [`RawWindowHandle`] is only used in valid contexts. - pub unsafe fn get_handle(&self) -> HasRawWindowHandleWrapper { - HasRawWindowHandleWrapper(self.0) + pub unsafe fn get_handle(&self) -> ThreadLockedRawWindowHandleWrapper { + ThreadLockedRawWindowHandleWrapper(self.0) } } @@ -27,10 +32,22 @@ impl RawWindowHandleWrapper { unsafe impl Send for RawWindowHandleWrapper {} unsafe impl Sync for RawWindowHandleWrapper {} -pub struct HasRawWindowHandleWrapper(RawWindowHandle); +/// A [`RawWindowHandleWrapper`] that cannot be sent across threads. +/// +/// This safely exposes a [`RawWindowHandle`], but care must be taken to ensure that the construction itself is correct. +/// +/// This can only be constructed via the [`RawWindowHandleWrapper::get_handle()`] method; +/// be sure to read the safety docs there about platform-specific limitations. +/// In many cases, this should only be constructed on the main thread. +pub struct ThreadLockedRawWindowHandleWrapper(RawWindowHandle); // SAFE: the caller has validated that this is a valid context to get RawWindowHandle -unsafe impl HasRawWindowHandle for HasRawWindowHandleWrapper { +// as otherwise an instance of this type could not have been constructed +// NOTE: we cannot simply impl HasRawWindowHandle for RawWindowHandleWrapper, +// as the `raw_window_handle` method is safe. We cannot guarantee that all calls +// of this method are correct (as it may be off the main thread on an incompatible platform), +// and so exposing a safe method to get a `RawWindowHandle` directly would be UB. +unsafe impl HasRawWindowHandle for ThreadLockedRawWindowHandleWrapper { fn raw_window_handle(&self) -> RawWindowHandle { self.0 }