| 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 parsing the `$DISPLAY` environment variable |
| 80 | #[derive (Debug, Clone, PartialEq, Eq)] |
| 81 | #[non_exhaustive ] |
| 82 | pub 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" )] |
| 99 | impl Error for DisplayParsingError {} |
| 100 | |
| 101 | impl 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 ] |
| 126 | pub 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" )] |
| 178 | impl Error for ConnectError {} |
| 179 | |
| 180 | impl 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 | |
| 210 | impl From<ParseError> for ConnectError { |
| 211 | fn from(err: ParseError) -> Self { |
| 212 | ConnectError::ParseError(err) |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | impl From<DisplayParsingError> for ConnectError { |
| 217 | fn from(err: DisplayParsingError) -> Self { |
| 218 | ConnectError::DisplayParsingError(err) |
| 219 | } |
| 220 | } |
| 221 | |
| 222 | #[cfg (feature = "std" )] |
| 223 | impl From<std::io::Error> for ConnectError { |
| 224 | fn from(err: std::io::Error) -> Self { |
| 225 | ConnectError::IoError(err) |
| 226 | } |
| 227 | } |
| 228 | |