x11rb_protocol/
errors.rs

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) => {
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}