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