1use core::any::type_name;
7use core::fmt;
8use core::str;
9
10use alloc::string::String;
11use alloc::string::ToString;
12use x11rb_protocol::x11_utils::X11Error;
13use x11rb_protocol::{
14 errors::{ConnectError, ParseError},
15 protocol::xproto::{SetupAuthenticate, SetupFailed},
16};
17
18cfg_std! {
19 use std::error::Error as StdError;
20 use std::io::Error as IoError;
21 use std::io::ErrorKind;
22}
23
24cfg_std_unix! {
25 use nix::errno::Errno;
26}
27
28pub struct Error {
30 inner: Inner,
32 initialization: bool,
35}
36
37enum Inner {
42 #[allow(dead_code)]
44 Unsupported(Unsupported),
45 Message(String),
47 InvalidState(InvalidState),
51 CouldntParseDisplay {
53 from_env: bool,
56 },
57 Poisoned {
59 type_name: &'static str,
61 },
62 ParseError(ParseError),
64 SetupFailed(SetupFailure),
66 X11Error(X11Error),
68 MissingExtension {
70 name: &'static str,
72 },
73 RequestTooLarge {
75 x_len: usize,
77 max_len: usize,
79 },
80 #[cfg(feature = "async")]
82 AsyncSendInProgress {
83 seq: u64,
85 },
86 #[cfg(feature = "std")]
88 Io(IoError),
89}
90
91#[allow(dead_code)]
92#[derive(Clone, Copy)]
93pub(crate) enum Unsupported {
94 Fds,
95 Socket,
96}
97
98#[derive(Clone, Copy)]
103pub(crate) enum InvalidState {
104 UnexpectedFds,
105 NotEnoughSetup,
106 ScreenOutOfRange,
107 ZeroIdMask,
108 BadError,
109 XidsExhausted,
110}
111
112#[derive(Clone)]
114pub enum SetupFailure {
115 Failed(SetupFailed),
116 Authenticate(SetupAuthenticate),
117}
118
119impl Error {
121 fn from_inner(inner: Inner) -> Self {
122 Self {
123 inner,
124 initialization: false,
125 }
126 }
127
128 pub(crate) fn make_invalid_state(is: InvalidState) -> Self {
129 Error::from_inner(Inner::InvalidState(is))
130 }
131
132 #[allow(dead_code)]
133 pub(crate) fn make_unsupported(us: Unsupported) -> Self {
134 Error::from_inner(Inner::Unsupported(us))
135 }
136
137 pub(crate) fn couldnt_parse_display(from_env: bool) -> Self {
138 Error::from_inner(Inner::CouldntParseDisplay { from_env })
139 }
140
141 pub(crate) fn make_poisoned<T>() -> Self {
142 Error::from_inner(Inner::Poisoned {
143 type_name: type_name::<T>(),
144 })
145 }
146
147 pub(crate) fn make_large_request(x_len: usize, max_len: usize) -> Self {
148 Error::from_inner(Inner::RequestTooLarge { x_len, max_len })
149 }
150
151 pub(crate) fn make_setup_failure(sf: SetupFailure) -> Self {
152 Error::from_inner(Inner::SetupFailed(sf))
153 }
154
155 pub(crate) fn make_connect_error(ce: ConnectError) -> Self {
156 let mut err = match ce {
158 ConnectError::ParseError(pe) => Error::make_parse_error(pe),
159 #[cfg(feature = "std")]
160 ConnectError::IoError(io) => Error::io(io),
161 ConnectError::InvalidScreen => {
162 Error::make_invalid_state(InvalidState::ScreenOutOfRange)
163 }
164 ConnectError::ZeroIdMask => Error::make_invalid_state(InvalidState::ZeroIdMask),
165 ConnectError::SetupFailed(sf) => Error::make_setup_failure(SetupFailure::Failed(sf)),
166 ConnectError::SetupAuthenticate(sa) => {
167 Error::make_setup_failure(SetupFailure::Authenticate(sa))
168 }
169 ConnectError::DisplayParsingError => Error::couldnt_parse_display(false),
170 ConnectError::Incomplete { .. } => {
171 Error::make_invalid_state(InvalidState::NotEnoughSetup)
172 }
173 _ => unreachable!(),
174 };
175
176 err.initialization = true;
177 err
178 }
179
180 pub(crate) fn would_block(&self) -> bool {
182 cfg_if::cfg_if! {
183 if #[cfg(feature = "std")] {
184 match self.as_io_error() {
185 Some(io) => io.kind() == ErrorKind::WouldBlock,
186 None => false,
187 }
188 } else {
189 false
190 }
191 }
192 }
193
194 #[allow(dead_code)]
195 pub(crate) fn is_protocol_error(&self) -> bool {
196 matches!(
197 self.inner,
198 Inner::X11Error(..) | Inner::MissingExtension { .. }
199 )
200 }
201}
202
203cfg_std! {
204 impl Error {
205 pub(crate) fn io(io: IoError) -> Self {
206 if !matches!(io.kind(), ErrorKind::WouldBlock) {
207 tracing::error!("encountered I/O error: {io:?}", io = io);
208 }
209 Error::from_inner(Inner::Io(io))
210 }
211 }
212}
213
214impl Error {
216 #[must_use]
219 pub fn make_msg<D: fmt::Display>(msg: D) -> Self {
220 Self::from_inner(Inner::Message(msg.to_string()))
221 }
222
223 #[must_use]
226 pub fn unsupported(&self) -> bool {
227 matches!(self.inner, Inner::Unsupported(_))
228 }
229
230 #[must_use]
232 pub fn make_parse_error(pe: ParseError) -> Self {
233 Error::from_inner(Inner::ParseError(pe))
234 }
235
236 #[must_use]
238 pub fn make_missing_extension(name: &'static str) -> Self {
239 Error::from_inner(Inner::MissingExtension { name })
240 }
241
242 #[must_use]
245 pub fn invalid_state(&self) -> bool {
246 #[allow(unused_mut)]
247 let mut base = matches!(self.inner, Inner::InvalidState(_) | Inner::Poisoned { .. });
248
249 cfg_if::cfg_if! {
250 if #[cfg(feature = "std")] {
251 base |= matches!(self.inner, Inner::Io(ref err) if err.kind() != ErrorKind::WouldBlock);
252 }
253 }
254
255 base
256 }
257
258 #[must_use]
261 pub fn initialization(&self) -> bool {
262 self.initialization
263 }
264
265 #[must_use]
267 pub fn as_setup_failure(&self) -> Option<&SetupFailure> {
268 match self.inner {
269 Inner::SetupFailed(ref sf) => Some(sf),
270 _ => None,
271 }
272 }
273
274 pub fn into_setup_failure(self) -> Result<SetupFailure> {
276 match self.inner {
277 Inner::SetupFailed(sf) => Ok(sf),
278 inner => Err(Self::from_inner(inner)),
279 }
280 }
281}
282
283cfg_async! {
285 impl Error {
286 pub(crate) fn async_send_in_progress(seq: u64) -> Self {
287 Error::from_inner(Inner::AsyncSendInProgress { seq })
288 }
289 }
290}
291
292cfg_std! {
294 impl Error {
295 #[must_use]
297 pub fn as_io_error(&self) -> Option<&IoError> {
298 match self.inner {
299 Inner::Io(ref io) => Some(io),
300 _ => None,
301 }
302 }
303
304 pub fn into_io_error(self) -> core::result::Result<IoError, Self> {
306 match self.inner {
307 Inner::Io(io) => Ok(io),
308 inner => Err(Self::from_inner(inner)),
309 }
310 }
311 }
312}
313
314cfg_std_unix! {
316 impl Error {
317 pub(crate) fn nix(errno: Errno) -> Self {
318 Error::io(IoError::from_raw_os_error(errno as i32))
319 }
320 }
321}
322
323impl fmt::Debug for Error {
326 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
327 struct InnerRepr<'a>(&'a Inner);
328
329 impl<'a> fmt::Debug for InnerRepr<'a> {
330 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
331 match self.0 {
332 Inner::Unsupported(ref e) => write!(f, "Unsupported: {}", e),
333 Inner::Message(ref msg) => f.write_str(msg),
334 Inner::InvalidState(ref e) => write!(f, "InvalidState: {}", e),
335 Inner::CouldntParseDisplay { .. } => f.write_str("CouldntParseDisplay"),
336 Inner::Poisoned { type_name } => write!(f, "Poisoned({})", type_name),
337 Inner::ParseError(err) => write!(f, "ParseError: {}", err),
338 Inner::SetupFailed(SetupFailure::Authenticate(_)) => {
339 f.write_str("SetupFailed: could not authenticate")
340 }
341 Inner::SetupFailed(SetupFailure::Failed(fail)) => {
342 let reason = str::from_utf8(&fail.reason).unwrap_or("bad utf-8");
343 write!(f, "SetupFailed: {}", reason)
344 }
345 Inner::X11Error(x11) => fmt::Debug::fmt(x11, f),
346 Inner::MissingExtension { name } => {
347 write!(f, "MissingExtension: {}", name)
348 }
349 Inner::RequestTooLarge { x_len, max_len } => {
350 write!(f, "RequestTooLarge: {} > {}", x_len, max_len)
351 }
352 #[cfg(feature = "async")]
353 Inner::AsyncSendInProgress { seq } => {
354 write!(f, "AsyncSendInProgress: seq {}", seq)
355 }
356 #[cfg(feature = "std")]
357 Inner::Io(ref e) => write!(f, "{:?}", e),
358 }
359 }
360 }
361
362 f.debug_tuple("Error")
363 .field(&InnerRepr(&self.inner))
364 .finish()
365 }
366}
367
368impl fmt::Display for Error {
369 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370 match self.inner {
371 Inner::Unsupported(ref e) => write!(f, "attempted an unsupported operation: {}", e),
372 Inner::InvalidState(ref e) => write!(f, "entered an invalid state: {}", e),
373 Inner::CouldntParseDisplay { from_env: true } => {
374 f.write_str("could not parse the $DISPLAY environment variable")
375 }
376 Inner::Poisoned { type_name } => write!(f, "object of type {} poisoned", type_name),
377 Inner::CouldntParseDisplay { from_env: false } => {
378 f.write_str("could not parse the display string")
379 }
380 Inner::ParseError(ref err) => fmt::Display::fmt(err, f),
381 Inner::SetupFailed(SetupFailure::Authenticate(ref e)) => {
382 let reason = str::from_utf8(&e.reason).unwrap_or("<invalid utf8>");
383 write!(f, "could not authenticate to the X server: {}", reason)
384 }
385 Inner::SetupFailed(SetupFailure::Failed(ref e)) => {
386 let reason = str::from_utf8(&e.reason).unwrap_or("<invalid utf8>");
387 write!(f, "could not setup the X connection: {}", reason)
388 }
389 Inner::X11Error(ref x11) => {
390 write!(
391 f,
392 "a {:?} error occurred on sequence number {}",
393 x11.error_kind, x11.sequence,
394 )
395 }
396 Inner::MissingExtension { name } => {
397 write!(f, "missing extension: {}", name)
398 }
399 Inner::Message(ref msg) => f.write_str(msg),
400 Inner::RequestTooLarge { x_len, max_len } => {
401 write!(
402 f,
403 "Request of size {} bytes exceeds maximum length of {} bytes",
404 x_len * 4,
405 max_len * 4
406 )
407 }
408 #[cfg(feature = "async")]
409 Inner::AsyncSendInProgress { seq } => {
410 write!(f, "async send in progress for sequence {}", seq)
411 }
412 #[cfg(feature = "std")]
413 Inner::Io(ref e) => write!(f, "{}", e),
414 }
415 }
416}
417
418impl fmt::Display for Unsupported {
419 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
420 match *self {
421 Unsupported::Fds => f.write_str("file descriptors"),
422 Unsupported::Socket => f.write_str("unix sockets"),
423 }
424 }
425}
426
427impl fmt::Display for InvalidState {
428 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
429 match *self {
430 InvalidState::UnexpectedFds => f.write_str("unexpected file descriptors"),
431 InvalidState::NotEnoughSetup => f.write_str("not enough data for setup"),
432 InvalidState::ScreenOutOfRange => f.write_str("screen out of range"),
433 InvalidState::ZeroIdMask => f.write_str("zero id mask"),
434 InvalidState::BadError => f.write_str("misformatted error"),
435 InvalidState::XidsExhausted => f.write_str("server ran out of xids"),
436 }
437 }
438}
439
440impl From<X11Error> for Error {
442 fn from(x11: X11Error) -> Self {
443 Self::from_inner(Inner::X11Error(x11))
444 }
445}
446
447cfg_std! {
448 impl From<IoError> for Error {
449 fn from(e: IoError) -> Self {
450 Self::from_inner(Inner::Io(e))
451 }
452 }
453
454 impl StdError for Error {
455 fn source(&self) -> Option<&(dyn StdError + 'static)> {
456 match self.inner {
457 Inner::ParseError(ref pe) => Some(pe),
458 #[cfg(feature = "std")]
459 Inner::Io(ref e) => Some(e),
460 _ => None,
461 }
462 }
463 }
464}
465
466pub(crate) fn initialization<R>(f: impl FnOnce() -> Result<R>) -> Result<R> {
469 match f() {
470 Ok(r) => Ok(r),
471 Err(mut e) => {
472 e.initialization = true;
473 Err(e)
474 }
475 }
476}
477
478pub type Result<T = ()> = core::result::Result<T, Error>;