1use static_assertions::assert_impl_all;
2use std::{convert::Infallible, error, fmt, io, sync::Arc};
3use zbus_names::{Error as NamesError, InterfaceName, OwnedErrorName};
4use zvariant::{Error as VariantError, ObjectPath};
5
6use crate::{
7 fdo,
8 message::{Message, Type},
9};
10
11#[derive(Debug)]
15#[non_exhaustive]
16#[allow(clippy::upper_case_acronyms)]
17pub enum Error {
18 InterfaceNotFound,
20 Address(String),
22 InputOutput(Arc<io::Error>),
24 InvalidField,
26 ExcessData,
28 Variant(VariantError),
30 Names(NamesError),
32 IncorrectEndian,
34 Handshake(String),
36 InvalidReply,
38 MethodError(OwnedErrorName, Option<String>, Message),
42 MissingField,
44 InvalidGUID,
46 Unsupported,
48 FDO(Box<fdo::Error>),
50 NameTaken,
52 InvalidMatchRule,
56 Failure(String),
58 MissingParameter(&'static str),
60 InvalidSerial,
62 InterfaceExists(InterfaceName<'static>, ObjectPath<'static>),
64}
65
66assert_impl_all!(Error: Send, Sync, Unpin);
67
68impl PartialEq for Error {
69 fn eq(&self, other: &Self) -> bool {
70 match (self, other) {
71 (Self::Address(_), Self::Address(_)) => true,
72 (Self::InterfaceNotFound, Self::InterfaceNotFound) => true,
73 (Self::Handshake(_), Self::Handshake(_)) => true,
74 (Self::InvalidReply, Self::InvalidReply) => true,
75 (Self::ExcessData, Self::ExcessData) => true,
76 (Self::IncorrectEndian, Self::IncorrectEndian) => true,
77 (Self::MethodError(_, _, _), Self::MethodError(_, _, _)) => true,
78 (Self::MissingField, Self::MissingField) => true,
79 (Self::InvalidGUID, Self::InvalidGUID) => true,
80 (Self::InvalidSerial, Self::InvalidSerial) => true,
81 (Self::Unsupported, Self::Unsupported) => true,
82 (Self::FDO(s), Self::FDO(o)) => s == o,
83 (Self::InvalidField, Self::InvalidField) => true,
84 (Self::InvalidMatchRule, Self::InvalidMatchRule) => true,
85 (Self::Variant(s), Self::Variant(o)) => s == o,
86 (Self::Names(s), Self::Names(o)) => s == o,
87 (Self::NameTaken, Self::NameTaken) => true,
88 (Error::InputOutput(_), Self::InputOutput(_)) => false,
89 (Self::Failure(s1), Self::Failure(s2)) => s1 == s2,
90 (Self::InterfaceExists(s1, s2), Self::InterfaceExists(o1, o2)) => s1 == o1 && s2 == o2,
91 (_, _) => false,
92 }
93 }
94}
95
96impl error::Error for Error {
97 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
98 match self {
99 Error::InterfaceNotFound => None,
100 Error::Address(_) => None,
101 Error::InputOutput(e) => Some(e),
102 Error::ExcessData => None,
103 Error::Handshake(_) => None,
104 Error::IncorrectEndian => None,
105 Error::Variant(e) => Some(e),
106 Error::Names(e) => Some(e),
107 Error::InvalidReply => None,
108 Error::MethodError(_, _, _) => None,
109 Error::InvalidGUID => None,
110 Error::Unsupported => None,
111 Error::FDO(e) => Some(e),
112 Error::InvalidField => None,
113 Error::MissingField => None,
114 Error::NameTaken => None,
115 Error::InvalidMatchRule => None,
116 Error::Failure(_) => None,
117 Error::MissingParameter(_) => None,
118 Error::InvalidSerial => None,
119 Error::InterfaceExists(_, _) => None,
120 }
121 }
122}
123
124impl fmt::Display for Error {
125 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
126 match self {
127 Error::InterfaceNotFound => write!(f, "Interface not found"),
128 Error::Address(e) => write!(f, "address error: {e}"),
129 Error::ExcessData => write!(f, "excess data"),
130 Error::InputOutput(e) => write!(f, "I/O error: {e}"),
131 Error::Handshake(e) => write!(f, "D-Bus handshake failed: {e}"),
132 Error::IncorrectEndian => write!(f, "incorrect endian"),
133 Error::InvalidField => write!(f, "invalid message field"),
134 Error::Variant(e) => write!(f, "{e}"),
135 Error::Names(e) => write!(f, "{e}"),
136 Error::InvalidReply => write!(f, "Invalid D-Bus method reply"),
137 Error::MissingField => write!(f, "A required field is missing from message headers"),
138 Error::MethodError(name, detail, _reply) => write!(
139 f,
140 "{}: {}",
141 **name,
142 detail.as_ref().map(|s| s.as_str()).unwrap_or("no details")
143 ),
144 Error::InvalidGUID => write!(f, "Invalid GUID"),
145 Error::Unsupported => write!(f, "Connection support is lacking"),
146 Error::FDO(e) => write!(f, "{e}"),
147 Error::NameTaken => write!(f, "name already taken on the bus"),
148 Error::InvalidMatchRule => write!(f, "Invalid match rule string"),
149 Error::Failure(e) => write!(f, "{e}"),
150 Error::MissingParameter(p) => {
151 write!(f, "Parameter `{}` was not specified but it is required", p)
152 }
153 Error::InvalidSerial => write!(f, "Serial number in the message header is 0"),
154 Error::InterfaceExists(i, p) => write!(f, "Interface `{i}` already exists at `{p}`"),
155 }
156 }
157}
158
159impl Clone for Error {
160 fn clone(&self) -> Self {
161 match self {
162 Error::InterfaceNotFound => Error::InterfaceNotFound,
163 Error::Address(e) => Error::Address(e.clone()),
164 Error::ExcessData => Error::ExcessData,
165 Error::InputOutput(e) => Error::InputOutput(e.clone()),
166 Error::Handshake(e) => Error::Handshake(e.clone()),
167 Error::IncorrectEndian => Error::IncorrectEndian,
168 Error::InvalidField => Error::InvalidField,
169 Error::Variant(e) => Error::Variant(e.clone()),
170 Error::Names(e) => Error::Names(e.clone()),
171 Error::InvalidReply => Error::InvalidReply,
172 Error::MissingField => Error::MissingField,
173 Error::MethodError(name, detail, reply) => {
174 Error::MethodError(name.clone(), detail.clone(), reply.clone())
175 }
176 Error::InvalidGUID => Error::InvalidGUID,
177 Error::Unsupported => Error::Unsupported,
178 Error::FDO(e) => Error::FDO(e.clone()),
179 Error::NameTaken => Error::NameTaken,
180 Error::InvalidMatchRule => Error::InvalidMatchRule,
181 Error::Failure(e) => Error::Failure(e.clone()),
182 Error::MissingParameter(p) => Error::MissingParameter(p),
183 Error::InvalidSerial => Error::InvalidSerial,
184 Error::InterfaceExists(i, p) => Error::InterfaceExists(i.clone(), p.clone()),
185 }
186 }
187}
188
189impl From<io::Error> for Error {
190 fn from(val: io::Error) -> Self {
191 Error::InputOutput(Arc::new(val))
192 }
193}
194
195#[cfg(unix)]
196impl From<nix::Error> for Error {
197 fn from(val: nix::Error) -> Self {
198 io::Error::from_raw_os_error(val as i32).into()
199 }
200}
201
202impl From<VariantError> for Error {
203 fn from(val: VariantError) -> Self {
204 Error::Variant(val)
205 }
206}
207
208impl From<NamesError> for Error {
209 fn from(val: NamesError) -> Self {
210 match val {
211 NamesError::Variant(e) => Error::Variant(e),
212 e => Error::Names(e),
213 }
214 }
215}
216
217impl From<fdo::Error> for Error {
218 fn from(val: fdo::Error) -> Self {
219 match val {
220 fdo::Error::ZBus(e) => e,
221 e => Error::FDO(Box::new(e)),
222 }
223 }
224}
225
226impl From<Infallible> for Error {
227 fn from(i: Infallible) -> Self {
228 match i {}
229 }
230}
231
232impl From<Message> for Error {
234 fn from(message: Message) -> Error {
235 let header = message.header();
238 if header.primary().msg_type() != Type::Error {
239 return Error::InvalidReply;
240 }
241
242 if let Some(name) = header.error_name() {
243 let name = name.to_owned().into();
244 match message.body().deserialize_unchecked::<&str>() {
245 Ok(detail) => Error::MethodError(name, Some(String::from(detail)), message),
246 Err(_) => Error::MethodError(name, None, message),
247 }
248 } else {
249 Error::InvalidReply
250 }
251 }
252}
253
254pub type Result<T> = std::result::Result<T, Error>;