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 connecting to an X11 server |
80 | #[derive (Debug)] |
81 | #[non_exhaustive ] |
82 | pub 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" )] |
134 | impl Error for ConnectError {} |
135 | |
136 | impl 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 | |
166 | impl From<ParseError> for ConnectError { |
167 | fn from(err: ParseError) -> Self { |
168 | ConnectError::ParseError(err) |
169 | } |
170 | } |
171 | |
172 | #[cfg (feature = "std" )] |
173 | impl From<std::io::Error> for ConnectError { |
174 | fn from(err: std::io::Error) -> Self { |
175 | ConnectError::IoError(err) |
176 | } |
177 | } |
178 | |