| 1 | use raw_window_handle::{HandleError, RawDisplayHandle, RawWindowHandle}; |
| 2 | use std::error::Error; |
| 3 | use std::fmt; |
| 4 | use std::num::NonZeroU32; |
| 5 | |
| 6 | #[derive (Debug)] |
| 7 | #[non_exhaustive ] |
| 8 | /// A sum type of all of the errors that can occur during the operation of this crate. |
| 9 | pub enum SoftBufferError { |
| 10 | /// A [`raw-window-handle`] error occurred. |
| 11 | /// |
| 12 | /// [`raw-window-handle`]: raw_window_handle |
| 13 | RawWindowHandle(HandleError), |
| 14 | |
| 15 | /// The [`RawDisplayHandle`] passed into [`Context::new`] is not supported by this crate. |
| 16 | /// |
| 17 | /// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle |
| 18 | /// [`Context::new`]: crate::Context::new |
| 19 | UnsupportedDisplayPlatform { |
| 20 | /// The platform name of the display that was passed into [`Context::new`]. |
| 21 | /// |
| 22 | /// This is a human-readable string that describes the platform of the display that was |
| 23 | /// passed into [`Context::new`]. The value is not guaranteed to be stable and this |
| 24 | /// exists for debugging purposes only. |
| 25 | /// |
| 26 | /// [`Context::new`]: crate::Context::new |
| 27 | human_readable_display_platform_name: &'static str, |
| 28 | |
| 29 | /// The [`RawDisplayHandle`] that was passed into [`Context::new`]. |
| 30 | /// |
| 31 | /// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle |
| 32 | /// [`Context::new`]: crate::Context::new |
| 33 | display_handle: RawDisplayHandle, |
| 34 | }, |
| 35 | |
| 36 | /// The [`RawWindowHandle`] passed into [`Surface::new`] is not supported by this crate. |
| 37 | /// |
| 38 | /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle |
| 39 | /// [`Surface::new`]: crate::Surface::new |
| 40 | UnsupportedWindowPlatform { |
| 41 | /// The platform name of the window that was passed into [`Surface::new`]. |
| 42 | /// |
| 43 | /// This is a human-readable string that describes the platform of the window that was |
| 44 | /// passed into [`Surface::new`]. The value is not guaranteed to be stable and this |
| 45 | /// exists for debugging purposes only. |
| 46 | /// |
| 47 | /// [`Surface::new`]: crate::Surface::new |
| 48 | human_readable_window_platform_name: &'static str, |
| 49 | |
| 50 | /// The platform name of the display used by the [`Context`]. |
| 51 | /// |
| 52 | /// It is possible for a window to be created on a different type of display than the |
| 53 | /// display that was passed into [`Context::new`]. This is a human-readable string that |
| 54 | /// describes the platform of the display that was passed into [`Context::new`]. The value |
| 55 | /// is not guaranteed to be stable and this exists for debugging purposes only. |
| 56 | /// |
| 57 | /// [`Context`]: crate::Context |
| 58 | /// [`Context::new`]: crate::Context::new |
| 59 | human_readable_display_platform_name: &'static str, |
| 60 | |
| 61 | /// The [`RawWindowHandle`] that was passed into [`Surface::new`]. |
| 62 | /// |
| 63 | /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle |
| 64 | /// [`Surface::new`]: crate::Surface::new |
| 65 | window_handle: RawWindowHandle, |
| 66 | }, |
| 67 | |
| 68 | /// The [`RawWindowHandle`] passed into [`Surface::new`] is missing necessary fields. |
| 69 | /// |
| 70 | /// [`RawWindowHandle`]: raw_window_handle::RawWindowHandle |
| 71 | /// [`Surface::new`]: crate::Surface::new |
| 72 | IncompleteWindowHandle, |
| 73 | |
| 74 | /// The [`RawDisplayHandle`] passed into [`Context::new`] is missing necessary fields. |
| 75 | /// |
| 76 | /// [`RawDisplayHandle`]: raw_window_handle::RawDisplayHandle |
| 77 | /// [`Context::new`]: crate::Context::new |
| 78 | IncompleteDisplayHandle, |
| 79 | |
| 80 | /// The provided size is outside of the range supported by the backend. |
| 81 | SizeOutOfRange { |
| 82 | /// The width that was out of range. |
| 83 | width: NonZeroU32, |
| 84 | |
| 85 | /// The height that was out of range. |
| 86 | height: NonZeroU32, |
| 87 | }, |
| 88 | |
| 89 | /// The provided damage rect is outside of the range supported by the backend. |
| 90 | DamageOutOfRange { |
| 91 | /// The damage rect that was out of range. |
| 92 | rect: crate::Rect, |
| 93 | }, |
| 94 | |
| 95 | /// A platform-specific backend error occurred. |
| 96 | /// |
| 97 | /// The first field provides a human-readable description of the error. The second field |
| 98 | /// provides the actual error that occurred. Note that the second field is, under the hood, |
| 99 | /// a private wrapper around the actual error, preventing the user from downcasting to the |
| 100 | /// actual error type. |
| 101 | PlatformError(Option<String>, Option<Box<dyn Error>>), |
| 102 | |
| 103 | /// This function is unimplemented on this platform. |
| 104 | Unimplemented, |
| 105 | } |
| 106 | |
| 107 | impl fmt::Display for SoftBufferError { |
| 108 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 109 | match self { |
| 110 | Self::RawWindowHandle(err) => fmt::Display::fmt(err, f), |
| 111 | Self::UnsupportedDisplayPlatform { |
| 112 | human_readable_display_platform_name, |
| 113 | display_handle, |
| 114 | } => write!( |
| 115 | f, |
| 116 | "The provided display returned an unsupported platform: {}. \nDisplay handle: {:?}" , |
| 117 | human_readable_display_platform_name, display_handle |
| 118 | ), |
| 119 | Self::UnsupportedWindowPlatform { |
| 120 | human_readable_window_platform_name, |
| 121 | human_readable_display_platform_name, |
| 122 | window_handle, |
| 123 | } => write!( |
| 124 | f, |
| 125 | "The provided window returned an unsupported platform: {}, {}. \nWindow handle: {:?}" , |
| 126 | human_readable_window_platform_name, human_readable_display_platform_name, window_handle |
| 127 | ), |
| 128 | Self::IncompleteWindowHandle => write!(f, "The provided window handle is null." ), |
| 129 | Self::IncompleteDisplayHandle => write!(f, "The provided display handle is null." ), |
| 130 | Self::SizeOutOfRange { width, height } => write!( |
| 131 | f, |
| 132 | "Surface size {width}x {height} out of range for backend." , |
| 133 | ), |
| 134 | Self::PlatformError(msg, None) => write!(f, "Platform error: {msg:?}" ), |
| 135 | Self::PlatformError(msg, Some(err)) => write!(f, "Platform error: {msg:?}: {err}" ), |
| 136 | Self::DamageOutOfRange { rect } => write!( |
| 137 | f, |
| 138 | "Damage rect {}x {} at ( {}, {}) out of range for backend." , |
| 139 | rect.width, rect.height, rect.x, rect.y |
| 140 | ), |
| 141 | Self::Unimplemented => write!(f, "This function is unimplemented on this platform." ), |
| 142 | } |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | impl std::error::Error for SoftBufferError { |
| 147 | fn source(&self) -> Option<&(dyn Error + 'static)> { |
| 148 | match self { |
| 149 | Self::RawWindowHandle(err: &HandleError) => Some(err), |
| 150 | Self::PlatformError(_, err: &Option>) => err.as_deref(), |
| 151 | _ => None, |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
| 156 | impl From<HandleError> for SoftBufferError { |
| 157 | fn from(err: HandleError) -> Self { |
| 158 | Self::RawWindowHandle(err) |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | /// Simple unit error type used to bubble up rejected platforms. |
| 163 | pub(crate) enum InitError<D> { |
| 164 | /// Failed to initialize. |
| 165 | Failure(SoftBufferError), |
| 166 | |
| 167 | /// Cannot initialize this handle on this platform. |
| 168 | Unsupported(D), |
| 169 | } |
| 170 | |
| 171 | impl<T> From<SoftBufferError> for InitError<T> { |
| 172 | fn from(err: SoftBufferError) -> Self { |
| 173 | Self::Failure(err) |
| 174 | } |
| 175 | } |
| 176 | |
| 177 | impl<T> From<HandleError> for InitError<T> { |
| 178 | fn from(err: HandleError) -> Self { |
| 179 | Self::Failure(err.into()) |
| 180 | } |
| 181 | } |
| 182 | |
| 183 | /// Convenient wrapper to cast errors into SoftBufferError. |
| 184 | #[allow (dead_code)] |
| 185 | pub(crate) trait SwResultExt<T> { |
| 186 | fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError>; |
| 187 | } |
| 188 | |
| 189 | impl<T, E: std::error::Error + 'static> SwResultExt<T> for Result<T, E> { |
| 190 | fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError> { |
| 191 | self.map_err(|e: E| { |
| 192 | SoftBufferError::PlatformError(Some(msg.into()), Some(Box::new(LibraryError(e)))) |
| 193 | }) |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | impl<T> SwResultExt<T> for Option<T> { |
| 198 | fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError> { |
| 199 | self.ok_or_else(|| SoftBufferError::PlatformError(Some(msg.into()), None)) |
| 200 | } |
| 201 | } |
| 202 | |
| 203 | /// A wrapper around a library error. |
| 204 | /// |
| 205 | /// This prevents `x11-dl` and `x11rb` from becoming public dependencies, since users cannot downcast |
| 206 | /// to this type. |
| 207 | struct LibraryError<E>(E); |
| 208 | |
| 209 | impl<E: fmt::Debug> fmt::Debug for LibraryError<E> { |
| 210 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 211 | fmt::Debug::fmt(&self.0, f) |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | impl<E: fmt::Display> fmt::Display for LibraryError<E> { |
| 216 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 217 | fmt::Display::fmt(&self.0, f) |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | impl<E: fmt::Debug + fmt::Display> std::error::Error for LibraryError<E> {} |
| 222 | |