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 | |