softbuffer/error.rs
1use raw_window_handle::{HandleError, RawDisplayHandle, RawWindowHandle};
2use std::error::Error;
3use std::fmt;
4use 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.
9pub 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
107impl 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
146impl std::error::Error for SoftBufferError {
147 fn source(&self) -> Option<&(dyn Error + 'static)> {
148 match self {
149 Self::RawWindowHandle(err) => Some(err),
150 Self::PlatformError(_, err) => err.as_deref(),
151 _ => None,
152 }
153 }
154}
155
156impl 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.
163pub(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
171impl<T> From<SoftBufferError> for InitError<T> {
172 fn from(err: SoftBufferError) -> Self {
173 Self::Failure(err)
174 }
175}
176
177impl<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.
184pub(crate) trait SwResultExt<T> {
185 fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError>;
186}
187
188impl<T, E: std::error::Error + 'static> SwResultExt<T> for Result<T, E> {
189 fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError> {
190 self.map_err(|e| {
191 SoftBufferError::PlatformError(Some(msg.into()), Some(Box::new(LibraryError(e))))
192 })
193 }
194}
195
196impl<T> SwResultExt<T> for Option<T> {
197 fn swbuf_err(self, msg: impl Into<String>) -> Result<T, SoftBufferError> {
198 self.ok_or_else(|| SoftBufferError::PlatformError(Some(msg.into()), None))
199 }
200}
201
202/// A wrapper around a library error.
203///
204/// This prevents `x11-dl` and `x11rb` from becoming public dependencies, since users cannot downcast
205/// to this type.
206struct LibraryError<E>(E);
207
208impl<E: fmt::Debug> fmt::Debug for LibraryError<E> {
209 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
210 fmt::Debug::fmt(&self.0, f)
211 }
212}
213
214impl<E: fmt::Display> fmt::Display for LibraryError<E> {
215 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 fmt::Display::fmt(&self.0, f)
217 }
218}
219
220impl<E: fmt::Debug + fmt::Display> std::error::Error for LibraryError<E> {}