1//! This module contains the current mess that is error handling.
2
3use crate::protocol::xproto::{SetupAuthenticate, SetupFailed};
4
5pub use crate::id_allocator::IdsExhausted;
6
7use core::fmt;
8
9#[cfg(feature = "std")]
10use std::error::Error;
11
12/// An error occurred while parsing some data
13#[derive(Debug, Copy, Clone, PartialEq, Eq)]
14#[non_exhaustive]
15pub 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")]
58impl Error for ParseError {}
59
60impl 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]
82pub 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")]
99impl Error for DisplayParsingError {}
100
101impl 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]
126pub 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")]
178impl Error for ConnectError {}
179
180impl 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
210impl From<ParseError> for ConnectError {
211 fn from(err: ParseError) -> Self {
212 ConnectError::ParseError(err)
213 }
214}
215
216impl From<DisplayParsingError> for ConnectError {
217 fn from(err: DisplayParsingError) -> Self {
218 ConnectError::DisplayParsingError(err)
219 }
220}
221
222#[cfg(feature = "std")]
223impl From<std::io::Error> for ConnectError {
224 fn from(err: std::io::Error) -> Self {
225 ConnectError::IoError(err)
226 }
227}
228