1use std::{convert::Infallible, error, fmt, io, sync::Arc};
2use zbus_names::{Error as NamesError, InterfaceName, OwnedErrorName};
3use zvariant::{Error as VariantError, ObjectPath};
4
5use crate::{
6 fdo,
7 message::{Message, Type},
8};
9
10#[derive(Debug)]
14#[non_exhaustive]
15#[allow(clippy::upper_case_acronyms)]
16pub enum Error {
17 InterfaceNotFound,
19 Address(String),
21 InputOutput(Arc<io::Error>),
23 InvalidField,
25 ExcessData,
27 Variant(VariantError),
29 Names(NamesError),
31 IncorrectEndian,
33 Handshake(String),
35 InvalidReply,
37 MethodError(OwnedErrorName, Option<String>, Message),
41 MissingField,
43 InvalidGUID,
45 Unsupported,
47 FDO(Box<fdo::Error>),
49 NameTaken,
51 InvalidMatchRule,
55 Failure(String),
57 MissingParameter(&'static str),
59 InvalidSerial,
61 InterfaceExists(InterfaceName<'static>, ObjectPath<'static>),
63}
64
65impl PartialEq for Error {
66 fn eq(&self, other: &Self) -> bool {
67 match (self, other) {
68 (Self::Address(_), Self::Address(_)) => true,
69 (Self::InterfaceNotFound, Self::InterfaceNotFound) => true,
70 (Self::Handshake(_), Self::Handshake(_)) => true,
71 (Self::InvalidReply, Self::InvalidReply) => true,
72 (Self::ExcessData, Self::ExcessData) => true,
73 (Self::IncorrectEndian, Self::IncorrectEndian) => true,
74 (Self::MethodError(_, _, _), Self::MethodError(_, _, _)) => true,
75 (Self::MissingField, Self::MissingField) => true,
76 (Self::InvalidGUID, Self::InvalidGUID) => true,
77 (Self::InvalidSerial, Self::InvalidSerial) => true,
78 (Self::Unsupported, Self::Unsupported) => true,
79 (Self::FDO(s), Self::FDO(o)) => s == o,
80 (Self::InvalidField, Self::InvalidField) => true,
81 (Self::InvalidMatchRule, Self::InvalidMatchRule) => true,
82 (Self::Variant(s), Self::Variant(o)) => s == o,
83 (Self::Names(s), Self::Names(o)) => s == o,
84 (Self::NameTaken, Self::NameTaken) => true,
85 (Error::InputOutput(_), Self::InputOutput(_)) => false,
86 (Self::Failure(s1), Self::Failure(s2)) => s1 == s2,
87 (Self::InterfaceExists(s1, s2), Self::InterfaceExists(o1, o2)) => s1 == o1 && s2 == o2,
88 (_, _) => false,
89 }
90 }
91}
92
93impl error::Error for Error {
94 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
95 match self {
96 Error::InterfaceNotFound => None,
97 Error::Address(_) => None,
98 Error::InputOutput(e) => Some(e),
99 Error::ExcessData => None,
100 Error::Handshake(_) => None,
101 Error::IncorrectEndian => None,
102 Error::Variant(e) => Some(e),
103 Error::Names(e) => Some(e),
104 Error::InvalidReply => None,
105 Error::MethodError(_, _, _) => None,
106 Error::InvalidGUID => None,
107 Error::Unsupported => None,
108 Error::FDO(e) => Some(e),
109 Error::InvalidField => None,
110 Error::MissingField => None,
111 Error::NameTaken => None,
112 Error::InvalidMatchRule => None,
113 Error::Failure(_) => None,
114 Error::MissingParameter(_) => None,
115 Error::InvalidSerial => None,
116 Error::InterfaceExists(_, _) => None,
117 }
118 }
119}
120
121impl fmt::Display for Error {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 match self {
124 Error::InterfaceNotFound => write!(f, "Interface not found"),
125 Error::Address(e) => write!(f, "address error: {e}"),
126 Error::ExcessData => write!(f, "excess data"),
127 Error::InputOutput(e) => write!(f, "I/O error: {e}"),
128 Error::Handshake(e) => write!(f, "D-Bus handshake failed: {e}"),
129 Error::IncorrectEndian => write!(f, "incorrect endian"),
130 Error::InvalidField => write!(f, "invalid message field"),
131 Error::Variant(e) => write!(f, "{e}"),
132 Error::Names(e) => write!(f, "{e}"),
133 Error::InvalidReply => write!(f, "Invalid D-Bus method reply"),
134 Error::MissingField => write!(f, "A required field is missing from message headers"),
135 Error::MethodError(name, detail, _reply) => write!(
136 f,
137 "{}: {}",
138 **name,
139 detail.as_ref().map(|s| s.as_str()).unwrap_or("no details")
140 ),
141 Error::InvalidGUID => write!(f, "Invalid GUID"),
142 Error::Unsupported => write!(f, "Connection support is lacking"),
143 Error::FDO(e) => write!(f, "{e}"),
144 Error::NameTaken => write!(f, "name already taken on the bus"),
145 Error::InvalidMatchRule => write!(f, "Invalid match rule string"),
146 Error::Failure(e) => write!(f, "{e}"),
147 Error::MissingParameter(p) => {
148 write!(f, "Parameter `{p}` was not specified but it is required")
149 }
150 Error::InvalidSerial => write!(f, "Serial number in the message header is 0"),
151 Error::InterfaceExists(i, p) => write!(f, "Interface `{i}` already exists at `{p}`"),
152 }
153 }
154}
155
156impl Error {
157 pub fn description(&self) -> Option<&str> {
163 match self {
164 Error::InterfaceNotFound => Some("interface not found"),
165 Error::Address(e) => Some(e),
166 Error::ExcessData => Some("excess data"),
167 Error::InputOutput(_) => Some("i/o error"),
168 Error::Handshake(e) => Some(e),
169 Error::IncorrectEndian => Some("incorrect endian"),
170 Error::InvalidField => Some("invalid field"),
171 Error::Variant(_) => Some("variant error"),
172 Error::Names(_) => Some("names error"),
173 Error::InvalidReply => Some("invalid reply"),
174 Error::MissingField => Some("a required field is missing from message headers"),
175 Error::MethodError(_, desc, _) => desc.as_deref(),
176 Error::InvalidGUID => Some("invalid GUID"),
177 Error::Unsupported => Some("connection support is lacking"),
178 Error::FDO(_) => Some("FDO error"),
179 Error::NameTaken => Some("name already taken on the bus"),
180 Error::InvalidMatchRule => Some("invalid match rule string"),
181 Error::Failure(e) => Some(e),
182 Error::MissingParameter(_) => Some("A required parameter is missing"),
183 Error::InvalidSerial => Some("serial number in the message header is 0"),
184 Error::InterfaceExists(_, _) => Some("interface already exists"),
185 }
186 }
187}
188
189impl Clone for Error {
190 fn clone(&self) -> Self {
191 match self {
192 Error::InterfaceNotFound => Error::InterfaceNotFound,
193 Error::Address(e) => Error::Address(e.clone()),
194 Error::ExcessData => Error::ExcessData,
195 Error::InputOutput(e) => Error::InputOutput(e.clone()),
196 Error::Handshake(e) => Error::Handshake(e.clone()),
197 Error::IncorrectEndian => Error::IncorrectEndian,
198 Error::InvalidField => Error::InvalidField,
199 Error::Variant(e) => Error::Variant(e.clone()),
200 Error::Names(e) => Error::Names(e.clone()),
201 Error::InvalidReply => Error::InvalidReply,
202 Error::MissingField => Error::MissingField,
203 Error::MethodError(name, detail, reply) => {
204 Error::MethodError(name.clone(), detail.clone(), reply.clone())
205 }
206 Error::InvalidGUID => Error::InvalidGUID,
207 Error::Unsupported => Error::Unsupported,
208 Error::FDO(e) => Error::FDO(e.clone()),
209 Error::NameTaken => Error::NameTaken,
210 Error::InvalidMatchRule => Error::InvalidMatchRule,
211 Error::Failure(e) => Error::Failure(e.clone()),
212 Error::MissingParameter(p) => Error::MissingParameter(p),
213 Error::InvalidSerial => Error::InvalidSerial,
214 Error::InterfaceExists(i, p) => Error::InterfaceExists(i.clone(), p.clone()),
215 }
216 }
217}
218
219impl From<io::Error> for Error {
220 fn from(val: io::Error) -> Self {
221 Error::InputOutput(Arc::new(val))
222 }
223}
224
225#[cfg(unix)]
226impl From<nix::Error> for Error {
227 fn from(val: nix::Error) -> Self {
228 io::Error::from_raw_os_error(val as i32).into()
229 }
230}
231
232impl From<VariantError> for Error {
233 fn from(val: VariantError) -> Self {
234 Error::Variant(val)
235 }
236}
237
238impl From<zvariant::signature::Error> for Error {
239 fn from(e: zvariant::signature::Error) -> Self {
240 zvariant::Error::from(e).into()
241 }
242}
243
244impl From<NamesError> for Error {
245 fn from(val: NamesError) -> Self {
246 match val {
247 NamesError::Variant(e) => Error::Variant(e),
248 e => Error::Names(e),
249 }
250 }
251}
252
253impl From<fdo::Error> for Error {
254 fn from(val: fdo::Error) -> Self {
255 match val {
256 fdo::Error::ZBus(e) => e,
257 e => Error::FDO(Box::new(e)),
258 }
259 }
260}
261
262impl From<Infallible> for Error {
263 fn from(i: Infallible) -> Self {
264 match i {}
265 }
266}
267
268impl From<Message> for Error {
270 fn from(message: Message) -> Error {
271 let header = message.header();
274 if header.primary().msg_type() != Type::Error {
275 return Error::InvalidReply;
276 }
277
278 if let Some(name) = header.error_name() {
279 let name = name.to_owned().into();
280 match message.body().deserialize_unchecked::<&str>() {
281 Ok(detail) => Error::MethodError(name, Some(String::from(detail)), message),
282 Err(_) => Error::MethodError(name, None, message),
283 }
284 } else {
285 Error::InvalidReply
286 }
287 }
288}
289
290pub type Result<T> = std::result::Result<T, Error>;