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 connecting to an X11 server
80#[derive(Debug)]
81#[non_exhaustive]
82pub enum ConnectError {
83 /// An unknown error occurred.
84 ///
85 /// One situation were this error is used when libxcb indicates an error that does not match
86 /// any of the defined error conditions. Thus, libxcb is violating its own API (or new error
87 /// cases were defined, but are not yet handled by x11rb).
88 UnknownError,
89
90 /// Error while parsing some data, see `ParseError`.
91 ParseError(ParseError),
92
93 /// Out of memory.
94 ///
95 /// This is `XCB_CONN_CLOSED_MEM_INSUFFICIENT`.
96 InsufficientMemory,
97
98 /// Error during parsing of display string.
99 ///
100 /// This is `XCB_CONN_CLOSED_PARSE_ERR`.
101 DisplayParsingError,
102
103 /// Server does not have a screen matching the display.
104 ///
105 /// This is `XCB_CONN_CLOSED_INVALID_SCREEN`.
106 InvalidScreen,
107
108 /// An I/O error occurred on the connection.
109 #[cfg(feature = "std")]
110 IoError(std::io::Error),
111
112 /// Invalid ID mask provided by the server.
113 ///
114 /// The value of `resource_id_mask` in the `Setup` provided by the server was zero.
115 ZeroIdMask,
116
117 /// The server rejected the connection with a `SetupAuthenticate` message.
118 SetupAuthenticate(SetupAuthenticate),
119
120 /// The server rejected the connection with a `SetupFailed` message.
121 SetupFailed(SetupFailed),
122
123 /// The client did not receive enough data from the server to complete
124 /// the handshake.
125 Incomplete {
126 /// The number of bytes that were expected.
127 expected: usize,
128 /// The number of bytes that were received.
129 received: usize,
130 },
131}
132
133#[cfg(feature = "std")]
134impl Error for ConnectError {}
135
136impl fmt::Display for ConnectError {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 fn display(f: &mut fmt::Formatter<'_>, prefix: &str, value: &[u8]) -> fmt::Result {
139 match core::str::from_utf8(value).ok() {
140 Some(value) => write!(f, "{}: '{}'", prefix, value),
141 None => write!(f, "{}: {:?} [message is not utf8]", prefix, value),
142 }
143 }
144 match self {
145 ConnectError::UnknownError => write!(f, "Unknown connection error"),
146 ConnectError::InsufficientMemory => write!(f, "Insufficient memory"),
147 ConnectError::DisplayParsingError => write!(f, "Display parsing error"),
148 ConnectError::InvalidScreen => write!(f, "Invalid screen"),
149 ConnectError::ParseError(err) => err.fmt(f),
150 #[cfg(feature = "std")]
151 ConnectError::IoError(err) => err.fmt(f),
152 ConnectError::ZeroIdMask => write!(f, "XID mask was zero"),
153 ConnectError::SetupFailed(err) => display(f, "X11 setup failed", &err.reason),
154 ConnectError::SetupAuthenticate(err) => {
155 display(f, "X11 authentication failed", &err.reason)
156 }
157 ConnectError::Incomplete { expected, received } => write!(
158 f,
159 "Not enough data received to complete the handshake. Expected {}, received {}",
160 expected, received
161 ),
162 }
163 }
164}
165
166impl From<ParseError> for ConnectError {
167 fn from(err: ParseError) -> Self {
168 ConnectError::ParseError(err)
169 }
170}
171
172#[cfg(feature = "std")]
173impl From<std::io::Error> for ConnectError {
174 fn from(err: std::io::Error) -> Self {
175 ConnectError::IoError(err)
176 }
177}
178