1 | //! This module contains the current mess that is error handling. |
2 | |
3 | use crate::protocol::xproto::{SetupAuthenticate, SetupFailed}; |
4 | |
5 | pub use crate::id_allocator::IdsExhausted; |
6 | |
7 | use core::fmt; |
8 | |
9 | #[cfg (feature = "std" )] |
10 | use std::error::Error; |
11 | |
12 | /// An error occurred while parsing some data |
13 | #[derive (Debug, Copy, Clone, PartialEq, Eq)] |
14 | #[non_exhaustive ] |
15 | pub enum ParseError { |
16 | /// Not enough data was provided. |
17 | InsufficientData, |
18 | |
19 | /// A value did not fit. |
20 | /// |
21 | /// This error can e.g. happen when a value that was received from the X11 server does not fit |
22 | /// into an `usize`. |
23 | ConversionFailed, |
24 | |
25 | /// The value of an expression could not be computed. |
26 | /// |
27 | /// As an example, the length of the data in `xproto`'s `GetPropertyReply` is described by |
28 | /// `value_len * (format / 8)`. The multiplication could cause an overflow, which would be |
29 | /// represented by this error. |
30 | InvalidExpression, |
31 | |
32 | /// A value was outside of its valid range. |
33 | /// |
34 | /// There are two kinds of situations where this error can happen: |
35 | /// |
36 | /// 1. The protocol was violated and a nonsensical value was found. |
37 | /// 2. The user of the API called the wrong parsing function. |
38 | /// |
39 | /// Examples for the first kind of error: |
40 | /// |
41 | /// - One of a set of values should be present (a `<switch>` in xcb-proto-speak), but none of |
42 | /// the `<cases>` matched. This can e.g. happen when parsing |
43 | /// [`crate::protocol::xinput::InputInfo`]. |
44 | /// - Parsing a request with a length field that is too small for the request header to fit. |
45 | /// |
46 | /// Examples for the second kind of error: |
47 | /// |
48 | /// - Parsing an X11 error with `response_type != 0`. |
49 | /// - Parsing an X11 reply with `response_type != 1`. |
50 | /// - Parsing an X11 request with the wrong value for its `minor_opcode`. |
51 | InvalidValue, |
52 | |
53 | /// Some file descriptors were expected, but not enough were received. |
54 | MissingFileDescriptors, |
55 | } |
56 | |
57 | #[cfg (feature = "std" )] |
58 | impl Error for ParseError {} |
59 | |
60 | impl fmt::Display for ParseError { |
61 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
62 | match self { |
63 | ParseError::InsufficientData => write!(f, "Insufficient data was provided" ), |
64 | ParseError::ConversionFailed => { |
65 | write!(f, "A value conversion failed due to out of range data" ) |
66 | } |
67 | ParseError::InvalidExpression => write!( |
68 | f, |
69 | "An expression could not be computed, e.g. due to overflow" |
70 | ), |
71 | ParseError::InvalidValue => { |
72 | write!(f, "A value could not be parsed into an enumeration" ) |
73 | } |
74 | ParseError::MissingFileDescriptors => write!(f, "Missing file descriptors" ), |
75 | } |
76 | } |
77 | } |
78 | |
79 | /// An error that occurred while parsing the `$DISPLAY` environment variable |
80 | #[derive (Debug, Clone, PartialEq, Eq)] |
81 | #[non_exhaustive ] |
82 | pub enum DisplayParsingError { |
83 | /// No explicit display was provided and the `$DISPLAY` environment variable is not set. |
84 | DisplayNotSet, |
85 | |
86 | /// The given value could not be parsed. The input to parsing is provided. |
87 | MalformedValue(alloc::boxed::Box<str>), |
88 | |
89 | /// The value of `$DISPLAY` is not valid unicode |
90 | NotUnicode, |
91 | |
92 | /// An unknown error occurred during display parsing. |
93 | /// |
94 | /// This is `XCB_CONN_CLOSED_PARSE_ERR`. |
95 | Unknown, |
96 | } |
97 | |
98 | #[cfg (feature = "std" )] |
99 | impl Error for DisplayParsingError {} |
100 | |
101 | impl fmt::Display for DisplayParsingError { |
102 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
103 | match self { |
104 | DisplayParsingError::DisplayNotSet => { |
105 | write!( |
106 | f, |
107 | "$DISPLAY variable not set and no value was provided explicitly" |
108 | ) |
109 | } |
110 | DisplayParsingError::MalformedValue(dpy: &Box) => { |
111 | write!(f, "Failed to parse value ' {}'" , dpy) |
112 | } |
113 | DisplayParsingError::NotUnicode => { |
114 | write!(f, "The value of $DISPLAY is not valid unicode" ) |
115 | } |
116 | DisplayParsingError::Unknown => { |
117 | write!(f, "Unknown error while parsing a $DISPLAY address" ) |
118 | } |
119 | } |
120 | } |
121 | } |
122 | |
123 | /// An error that occurred while connecting to an X11 server |
124 | #[derive (Debug)] |
125 | #[non_exhaustive ] |
126 | pub enum ConnectError { |
127 | /// An unknown error occurred. |
128 | /// |
129 | /// One situation were this error is used when libxcb indicates an error that does not match |
130 | /// any of the defined error conditions. Thus, libxcb is violating its own API (or new error |
131 | /// cases were defined, but are not yet handled by x11rb). |
132 | UnknownError, |
133 | |
134 | /// Error while parsing some data, see `ParseError`. |
135 | ParseError(ParseError), |
136 | |
137 | /// Out of memory. |
138 | /// |
139 | /// This is `XCB_CONN_CLOSED_MEM_INSUFFICIENT`. |
140 | InsufficientMemory, |
141 | |
142 | /// Error during parsing of display string. |
143 | /// |
144 | /// This is `XCB_CONN_CLOSED_PARSE_ERR`. |
145 | DisplayParsingError(DisplayParsingError), |
146 | |
147 | /// Server does not have a screen matching the display. |
148 | /// |
149 | /// This is `XCB_CONN_CLOSED_INVALID_SCREEN`. |
150 | InvalidScreen, |
151 | |
152 | /// An I/O error occurred on the connection. |
153 | #[cfg (feature = "std" )] |
154 | IoError(std::io::Error), |
155 | |
156 | /// Invalid ID mask provided by the server. |
157 | /// |
158 | /// The value of `resource_id_mask` in the `Setup` provided by the server was zero. |
159 | ZeroIdMask, |
160 | |
161 | /// The server rejected the connection with a `SetupAuthenticate` message. |
162 | SetupAuthenticate(SetupAuthenticate), |
163 | |
164 | /// The server rejected the connection with a `SetupFailed` message. |
165 | SetupFailed(SetupFailed), |
166 | |
167 | /// The client did not receive enough data from the server to complete |
168 | /// the handshake. |
169 | Incomplete { |
170 | /// The number of bytes that were expected. |
171 | expected: usize, |
172 | /// The number of bytes that were received. |
173 | received: usize, |
174 | }, |
175 | } |
176 | |
177 | #[cfg (feature = "std" )] |
178 | impl Error for ConnectError {} |
179 | |
180 | impl fmt::Display for ConnectError { |
181 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
182 | fn display(f: &mut fmt::Formatter<'_>, prefix: &str, value: &[u8]) -> fmt::Result { |
183 | match core::str::from_utf8(value).ok() { |
184 | Some(value) => write!(f, " {}: ' {}'" , prefix, value), |
185 | None => write!(f, " {}: {:?} [message is not utf8]" , prefix, value), |
186 | } |
187 | } |
188 | match self { |
189 | ConnectError::UnknownError => write!(f, "Unknown connection error" ), |
190 | ConnectError::InsufficientMemory => write!(f, "Insufficient memory" ), |
191 | ConnectError::DisplayParsingError(err) => err.fmt(f), |
192 | ConnectError::InvalidScreen => write!(f, "Invalid screen" ), |
193 | ConnectError::ParseError(err) => err.fmt(f), |
194 | #[cfg (feature = "std" )] |
195 | ConnectError::IoError(err) => err.fmt(f), |
196 | ConnectError::ZeroIdMask => write!(f, "XID mask was zero" ), |
197 | ConnectError::SetupFailed(err) => display(f, "X11 setup failed" , &err.reason), |
198 | ConnectError::SetupAuthenticate(err) => { |
199 | display(f, "X11 authentication failed" , &err.reason) |
200 | } |
201 | ConnectError::Incomplete { expected, received } => write!( |
202 | f, |
203 | "Not enough data received to complete the handshake. Expected {}, received {}" , |
204 | expected, received |
205 | ), |
206 | } |
207 | } |
208 | } |
209 | |
210 | impl From<ParseError> for ConnectError { |
211 | fn from(err: ParseError) -> Self { |
212 | ConnectError::ParseError(err) |
213 | } |
214 | } |
215 | |
216 | impl From<DisplayParsingError> for ConnectError { |
217 | fn from(err: DisplayParsingError) -> Self { |
218 | ConnectError::DisplayParsingError(err) |
219 | } |
220 | } |
221 | |
222 | #[cfg (feature = "std" )] |
223 | impl From<std::io::Error> for ConnectError { |
224 | fn from(err: std::io::Error) -> Self { |
225 | ConnectError::IoError(err) |
226 | } |
227 | } |
228 | |