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 raw_*_handle return a result #122

Merged
merged 5 commits into from
Jun 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* **Breaking:** `HasRaw(Display/Window)Handle::raw_(display/window)_handle` returns a result indicating if fetching the window handle failed (#122).
* Remove Android-specific platform differences (#118).

## 0.5.2 (2023-03-31)
Expand Down
33 changes: 7 additions & 26 deletions src/borrowed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use core::fmt;
use core::hash::{Hash, Hasher};
use core::marker::PhantomData;

use crate::{HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle};
use crate::{
HandleError, HasRawDisplayHandle, HasRawWindowHandle, RawDisplayHandle, RawWindowHandle,
};

/// Keeps track of whether the application is currently active.
///
Expand Down Expand Up @@ -268,8 +270,8 @@ impl<'a> DisplayHandle<'a> {
}

unsafe impl HasRawDisplayHandle for DisplayHandle<'_> {
fn raw_display_handle(&self) -> RawDisplayHandle {
self.raw
fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError> {
Ok(self.raw)
}
}

Expand Down Expand Up @@ -411,8 +413,8 @@ impl<'a> WindowHandle<'a> {
}

unsafe impl HasRawWindowHandle for WindowHandle<'_> {
fn raw_window_handle(&self) -> RawWindowHandle {
self.raw
fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError> {
Ok(self.raw)
}
}

Expand All @@ -422,27 +424,6 @@ impl HasWindowHandle for WindowHandle<'_> {
}
}

/// The error type returned when a handle cannot be obtained.
#[derive(Debug)]
#[non_exhaustive]
pub enum HandleError {
/// The handle is not currently active.
///
/// See documentation on [`Active`] for more information.
Inactive,
}

impl fmt::Display for HandleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Inactive => write!(f, "the handle is not currently active"),
}
}
}

#[cfg(feature = "std")]
impl std::error::Error for HandleError {}

/// ```compile_fail
/// use raw_window_handle::{Active, DisplayHandle, WindowHandle};
/// fn _assert<T: Send + Sync>() {}
Expand Down
47 changes: 37 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ pub use appkit::{AppKitDisplayHandle, AppKitWindowHandle};
#[cfg(any(feature = "std", not(target_os = "android")))]
#[allow(deprecated)]
pub use borrowed::{
Active, ActiveHandle, DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle,
WindowHandle,
Active, ActiveHandle, DisplayHandle, HasDisplayHandle, HasWindowHandle, WindowHandle,
};
pub use haiku::{HaikuDisplayHandle, HaikuWindowHandle};
pub use redox::{OrbitalDisplayHandle, OrbitalWindowHandle};
Expand All @@ -61,6 +60,8 @@ pub use unix::{
pub use web::{WebDisplayHandle, WebWindowHandle};
pub use windows::{Win32WindowHandle, WinRtWindowHandle, WindowsDisplayHandle};

use core::fmt;

/// Window that wraps around a raw window handle.
///
/// # Safety
Expand All @@ -76,25 +77,25 @@ pub use windows::{Win32WindowHandle, WinRtWindowHandle, WindowsDisplayHandle};
/// The exact handles returned by `raw_window_handle` must remain consistent between multiple calls
/// to `raw_window_handle` as long as not indicated otherwise by platform specific events.
pub unsafe trait HasRawWindowHandle {
fn raw_window_handle(&self) -> RawWindowHandle;
fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError>;
}

unsafe impl<'a, T: HasRawWindowHandle + ?Sized> HasRawWindowHandle for &'a T {
fn raw_window_handle(&self) -> RawWindowHandle {
fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError> {
(*self).raw_window_handle()
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
unsafe impl<T: HasRawWindowHandle + ?Sized> HasRawWindowHandle for alloc::rc::Rc<T> {
fn raw_window_handle(&self) -> RawWindowHandle {
fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError> {
(**self).raw_window_handle()
}
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
unsafe impl<T: HasRawWindowHandle + ?Sized> HasRawWindowHandle for alloc::sync::Arc<T> {
fn raw_window_handle(&self) -> RawWindowHandle {
fn raw_window_handle(&self) -> Result<RawWindowHandle, HandleError> {
(**self).raw_window_handle()
}
}
Expand Down Expand Up @@ -216,27 +217,27 @@ pub enum RawWindowHandle {
/// The exact handles returned by `raw_display_handle` must remain consistent between multiple calls
/// to `raw_display_handle` as long as not indicated otherwise by platform specific events.
pub unsafe trait HasRawDisplayHandle {
fn raw_display_handle(&self) -> RawDisplayHandle;
fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError>;
}

unsafe impl<'a, T: HasRawDisplayHandle + ?Sized> HasRawDisplayHandle for &'a T {
fn raw_display_handle(&self) -> RawDisplayHandle {
fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError> {
(*self).raw_display_handle()
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
unsafe impl<T: HasRawDisplayHandle + ?Sized> HasRawDisplayHandle for alloc::rc::Rc<T> {
fn raw_display_handle(&self) -> RawDisplayHandle {
fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError> {
(**self).raw_display_handle()
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
unsafe impl<T: HasRawDisplayHandle + ?Sized> HasRawDisplayHandle for alloc::sync::Arc<T> {
fn raw_display_handle(&self) -> RawDisplayHandle {
fn raw_display_handle(&self) -> Result<RawDisplayHandle, HandleError> {
(**self).raw_display_handle()
}
}
Expand Down Expand Up @@ -344,6 +345,32 @@ pub enum RawDisplayHandle {
Haiku(HaikuDisplayHandle),
}

/// An error that can occur while fetching a display or window handle.
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum HandleError {
/// The underlying handle cannot be represented using the types in this crate.
NotSupported,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the use-case for this?

The use-case discussed in #104 would use Unavailable, since that's what most accurately describes their situation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the library can't provide a any handle for the current platform, but still somehow built for it. Or when multiple could be provided at the same time, like XLIB and XCB, but it was compiled without xlib, so it'll be not-available in generic cfg less code.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea is that:

  • NotSupported is when the underlying windowing system does not support returning any of the C window handles. For instance, if you're using a pure Rust implementation of X11 or Wayland, or if you're using something that raw-window-handle doesn't support (like a game console).
  • Unavailable is when the window is temporarily not available. The use case here is Android after a suspend event. There are probably others.

Handling these two error conditions may require separate code for certain cases.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be cool to have some of those example uses in the docs


/// The underlying handle is not available.
Unavailable,
}

impl fmt::Display for HandleError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NotSupported => write!(
f,
"The underlying handle cannot be represented using the types in this crate"
),
Self::Unavailable => write!(f, "The underlying handle is not available"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error Display text should start with a lowercase letter

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a precedent for this? I've always started my error messages with a capital letter.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well the Error trait itself recommends it

}
}
}

#[cfg(feature = "std")]
impl std::error::Error for HandleError {}

macro_rules! from_impl {
($($to:ident, $enum:ident, $from:ty)*) => ($(
impl From<$from> for $to {
Expand Down