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