1//! Contains structs and traits closely related to D-Bus messages.
2
3use std::{fmt, ptr};
4use super::{ffi, Error, libc, init_dbus};
5use crate::strings::{BusName, Path, Interface, Member, ErrorName};
6use std::ffi::CStr;
7
8use super::arg::{Append, AppendAll, IterAppend, ReadAll, Get, Iter, Arg, RefArg, TypeMismatchError};
9
10#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
11/// One of the four different message types.
12pub enum MessageType {
13 /// This is a method call D-Bus message
14 MethodCall = 1,
15 /// This is a method return Ok D-Bus message, used when the method call message was successfully processed
16 MethodReturn = 2,
17 /// This is a method return with error D-Bus message, used when the method call message could not be handled
18 Error = 3,
19 /// This is a signal, usually sent to whoever wants to listen
20 Signal = 4,
21}
22
23impl<'a> TryFrom<&'a str> for MessageType {
24 type Error = ();
25
26 fn try_from(value: &'a str) -> Result<Self, <crate::message::MessageType as TryFrom<&'a str>>::Error> {
27 match value {
28 "error" => Ok(MessageType::Error),
29 "method_call" => Ok(MessageType::MethodCall),
30 "method_return" => Ok(MessageType::MethodReturn),
31 "signal" => Ok(MessageType::Signal),
32 _ => Err(())
33 }
34 }
35}
36
37mod signalargs;
38pub use self::signalargs::SignalArgs;
39
40mod matchrule;
41pub use self::matchrule::MatchRule;
42use std::convert::TryFrom;
43
44mod parser;
45pub use self::parser::Error as MatchRuleParserError;
46
47/// A D-Bus message. A message contains headers - usually destination address, path, interface and member,
48/// and a list of arguments.
49pub struct Message {
50 msg: *mut ffi::DBusMessage,
51}
52
53unsafe impl Send for Message {}
54
55impl Message {
56 /// Creates a new method call message.
57 pub fn new_method_call<'d, 'p, 'i, 'm, D, P, I, M>(destination: D, path: P, iface: I, method: M) -> Result<Message, String>
58 where D: Into<BusName<'d>>, P: Into<Path<'p>>, I: Into<Interface<'i>>, M: Into<Member<'m>> {
59 init_dbus();
60 let (d, p, i, m) = (destination.into(), path.into(), iface.into(), method.into());
61 let ptr = unsafe {
62 ffi::dbus_message_new_method_call(d.as_ptr(), p.as_ptr(), i.as_ptr(), m.as_ptr())
63 };
64 if ptr.is_null() { Err("D-Bus error: dbus_message_new_method_call failed".into()) }
65 else { Ok(Message { msg: ptr}) }
66 }
67
68 /// Creates a new method call message.
69 pub fn method_call(destination: &BusName, path: &Path, iface: &Interface, name: &Member) -> Message {
70 init_dbus();
71 let ptr = unsafe {
72 ffi::dbus_message_new_method_call(destination.as_ptr(), path.as_ptr(),
73 iface.as_ptr(), name.as_ptr())
74 };
75 if ptr.is_null() { panic!("D-Bus error: dbus_message_new_method_call failed") }
76 Message { msg: ptr}
77 }
78
79 /// Creates a new message that is a replica of this message, but without a serial.
80 ///
81 /// May fail if out of memory or file descriptors.
82 pub fn duplicate(&self) -> Result<Self, String> {
83 let ptr = unsafe {
84 ffi::dbus_message_copy(self.msg)
85 };
86 if ptr.is_null() {
87 Err("D-Bus error: dbus_message_copy failed".into())
88 } else {
89 Ok(Message { msg: ptr })
90 }
91 }
92
93 /// Creates a new method call message.
94 pub fn call_with_args<'d, 'p, 'i, 'm, A, D, P, I, M>(destination: D, path: P, iface: I, method: M, args: A) -> Message
95 where D: Into<BusName<'d>>, P: Into<Path<'p>>, I: Into<Interface<'i>>, M: Into<Member<'m>>, A: AppendAll {
96 let mut msg = Message::method_call(&destination.into(), &path.into(), &iface.into(), &method.into());
97 msg.append_all(args);
98 msg
99 }
100
101 /// Creates a new signal message.
102 pub fn new_signal<P, I, M>(path: P, iface: I, name: M) -> Result<Message, String>
103 where P: Into<String>, I: Into<String>, M: Into<String> {
104 init_dbus();
105
106 let p = Path::new(path)?;
107 let i = Interface::new(iface)?;
108 let m = Member::new(name)?;
109
110 let ptr = unsafe {
111 ffi::dbus_message_new_signal(p.as_ptr(), i.as_ptr(), m.as_ptr())
112 };
113 if ptr.is_null() { Err("D-Bus error: dbus_message_new_signal failed".into()) }
114 else { Ok(Message { msg: ptr}) }
115 }
116
117 /// Creates a new signal message.
118 pub fn signal(path: &Path, iface: &Interface, name: &Member) -> Message {
119 init_dbus();
120 let ptr = unsafe {
121 ffi::dbus_message_new_signal(path.as_ptr(), iface.as_ptr(), name.as_ptr())
122 };
123 if ptr.is_null() { panic!("D-Bus error: dbus_message_new_signal failed") }
124 Message { msg: ptr}
125 }
126
127 /// Creates a method reply for this method call.
128 pub fn new_method_return(m: &Message) -> Option<Message> {
129 let ptr = unsafe { ffi::dbus_message_new_method_return(m.msg) };
130 if ptr.is_null() { None } else { Some(Message { msg: ptr} ) }
131 }
132
133 /// Creates a method return (reply) for this method call.
134 pub fn method_return(&self) -> Message {
135 let ptr = unsafe { ffi::dbus_message_new_method_return(self.msg) };
136 if ptr.is_null() { panic!("D-Bus error: dbus_message_new_method_return failed") }
137 Message {msg: ptr}
138 }
139
140 /// Creates a reply for a method call message.
141 ///
142 /// Panics if called for a message which is not a method call.
143 pub fn return_with_args<A: AppendAll>(&self, args: A) -> Message {
144 let mut m = self.method_return();
145 m.append_all(args);
146 m
147 }
148
149 /// Creates a new error reply
150 pub fn error(&self, error_name: &ErrorName, error_message: &CStr) -> Message {
151 let ptr = unsafe { ffi::dbus_message_new_error(self.msg, error_name.as_ptr(), error_message.as_ptr()) };
152 if ptr.is_null() { panic!("D-Bus error: dbus_message_new_error failed") }
153 Message { msg: ptr}
154 }
155
156 /// Get the MessageItems that make up the message.
157 ///
158 /// Note: use `iter_init` or `get1`/`get2`/etc instead for faster access to the arguments.
159 /// This method is provided for backwards compatibility.
160 pub fn get_items(&self) -> Vec<crate::arg::messageitem::MessageItem> {
161 let mut i = self.iter_init();
162 let mut v = vec!();
163 while let Some(z) = crate::arg::messageitem::MessageItem::get(&mut i) { v.push(z); i.next(); }
164 v
165 }
166
167 /// Get the D-Bus serial of a message, if one was specified.
168 pub fn get_serial(&self) -> Option<u32> {
169 let x = unsafe { ffi::dbus_message_get_serial(self.msg) };
170 if x == 0 { None } else { Some(x) }
171 }
172
173 /// Get the serial of the message this message is a reply to, if present.
174 pub fn get_reply_serial(&self) -> Option<u32> {
175 let s = unsafe { ffi::dbus_message_get_reply_serial(self.msg) };
176 if s == 0 { None } else { Some(s) }
177 }
178
179 /// Returns true if the message does not expect a reply.
180 pub fn get_no_reply(&self) -> bool { unsafe { ffi::dbus_message_get_no_reply(self.msg) != 0 } }
181
182 /// Set whether or not the message expects a reply.
183 ///
184 /// Set to true if you send a method call and do not want a reply.
185 pub fn set_no_reply(&mut self, v: bool) {
186 unsafe { ffi::dbus_message_set_no_reply(self.msg, if v { 1 } else { 0 }) }
187 }
188
189 /// Returns true if the message can cause a service to be auto-started.
190 pub fn get_auto_start(&self) -> bool { unsafe { ffi::dbus_message_get_auto_start(self.msg) != 0 } }
191
192 /// Sets whether or not the message can cause a service to be auto-started.
193 ///
194 /// Defaults to true.
195 pub fn set_auto_start(&mut self, v: bool) {
196 unsafe { ffi::dbus_message_set_auto_start(self.msg, if v { 1 } else { 0 }) }
197 }
198
199 /// Add one or more MessageItems to this Message.
200 ///
201 /// Note: using `append1`, `append2` or `append3` might be faster, especially for large arrays.
202 /// This method is provided for backwards compatibility.
203 pub fn append_items(&mut self, v: &[crate::arg::messageitem::MessageItem]) {
204 let mut ia = IterAppend::new(self);
205 for a in v { a.append_by_ref(&mut ia); }
206 }
207
208 /// Appends one argument to this message.
209 /// Use in builder style: e g `m.method_return().append1(7i32)`
210 pub fn append1<A: Append>(mut self, a: A) -> Self {
211 {
212 let mut m = IterAppend::new(&mut self);
213 m.append(a);
214 }
215 self
216 }
217
218 /// Appends two arguments to this message.
219 /// Use in builder style: e g `m.method_return().append2(7i32, 6u8)`
220 pub fn append2<A1: Append, A2: Append>(mut self, a1: A1, a2: A2) -> Self {
221 {
222 let mut m = IterAppend::new(&mut self);
223 m.append(a1); m.append(a2);
224 }
225 self
226 }
227
228 /// Appends three arguments to this message.
229 /// Use in builder style: e g `m.method_return().append3(7i32, 6u8, true)`
230 pub fn append3<A1: Append, A2: Append, A3: Append>(mut self, a1: A1, a2: A2, a3: A3) -> Self {
231 {
232 let mut m = IterAppend::new(&mut self);
233 m.append(a1); m.append(a2); m.append(a3);
234 }
235 self
236 }
237
238 /// Appends RefArgs to this message.
239 /// Use in builder style: e g `m.method_return().append_ref(&[7i32, 6u8, true])`
240 pub fn append_ref<A: RefArg>(mut self, r: &[A]) -> Self {
241 {
242 let mut m = IterAppend::new(&mut self);
243 for rr in r {
244 rr.append(&mut m);
245 }
246 }
247 self
248 }
249
250 /// Appends arguments to a message.
251 pub fn append_all<A: AppendAll>(&mut self, a: A) {
252 let mut m = IterAppend::new(self);
253 a.append(&mut m);
254 }
255
256 /// Gets the first argument from the message, if that argument is of type G1.
257 /// Returns None if there are not enough arguments, or if types don't match.
258 pub fn get1<'a, G1: Get<'a>>(&'a self) -> Option<G1> {
259 let mut i = Iter::new(&self);
260 i.get()
261 }
262
263 /// Gets the first two arguments from the message, if those arguments are of type G1 and G2.
264 /// Returns None if there are not enough arguments, or if types don't match.
265 pub fn get2<'a, G1: Get<'a>, G2: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>) {
266 let mut i = Iter::new(&self);
267 let g1 = i.get();
268 if !i.next() { return (g1, None); }
269 (g1, i.get())
270 }
271
272 /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3.
273 /// Returns None if there are not enough arguments, or if types don't match.
274 pub fn get3<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>) {
275 let mut i = Iter::new(&self);
276 let g1 = i.get();
277 if !i.next() { return (g1, None, None) }
278 let g2 = i.get();
279 if !i.next() { return (g1, g2, None) }
280 (g1, g2, i.get())
281 }
282
283 /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4.
284 /// Returns None if there are not enough arguments, or if types don't match.
285 pub fn get4<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>) {
286 let mut i = Iter::new(&self);
287 let g1 = i.get();
288 if !i.next() { return (g1, None, None, None) }
289 let g2 = i.get();
290 if !i.next() { return (g1, g2, None, None) }
291 let g3 = i.get();
292 if !i.next() { return (g1, g2, g3, None) }
293 (g1, g2, g3, i.get())
294 }
295
296 /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3 and G4.
297 /// Returns None if there are not enough arguments, or if types don't match.
298 /// Note: If you need more than five arguments, use `iter_init` instead.
299 pub fn get5<'a, G1: Get<'a>, G2: Get<'a>, G3: Get<'a>, G4: Get<'a>, G5: Get<'a>>(&'a self) -> (Option<G1>, Option<G2>, Option<G3>, Option<G4>, Option<G5>) {
300 let mut i = Iter::new(&self);
301 let g1 = i.get();
302 if !i.next() { return (g1, None, None, None, None) }
303 let g2 = i.get();
304 if !i.next() { return (g1, g2, None, None, None) }
305 let g3 = i.get();
306 if !i.next() { return (g1, g2, g3, None, None) }
307 let g4 = i.get();
308 if !i.next() { return (g1, g2, g3, g4, None) }
309 (g1, g2, g3, g4, i.get())
310 }
311
312 /// Gets the first argument from the message, if that argument is of type G1.
313 ///
314 /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
315 pub fn read1<'a, G1: Arg + Get<'a>>(&'a self) -> Result<G1, TypeMismatchError> {
316 let mut i = Iter::new(&self);
317 i.read()
318 }
319
320 /// Gets the first two arguments from the message, if those arguments are of type G1 and G2.
321 ///
322 /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
323 pub fn read2<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>>(&'a self) -> Result<(G1, G2), TypeMismatchError> {
324 let mut i = Iter::new(&self);
325 Ok((i.read()?, i.read()?))
326 }
327
328 /// Gets the first three arguments from the message, if those arguments are of type G1, G2 and G3.
329 ///
330 /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
331 pub fn read3<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>>(&'a self) ->
332 Result<(G1, G2, G3), TypeMismatchError> {
333 let mut i = Iter::new(&self);
334 Ok((i.read()?, i.read()?, i.read()?))
335 }
336
337 /// Gets the first four arguments from the message, if those arguments are of type G1, G2, G3 and G4.
338 ///
339 /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
340 pub fn read4<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>>(&'a self) ->
341 Result<(G1, G2, G3, G4), TypeMismatchError> {
342 let mut i = Iter::new(&self);
343 Ok((i.read()?, i.read()?, i.read()?, i.read()?))
344 }
345
346 /// Gets the first five arguments from the message, if those arguments are of type G1, G2, G3, G4 and G5.
347 ///
348 /// Returns a TypeMismatchError if there are not enough arguments, or if types don't match.
349 /// Note: If you need more than five arguments, use `iter_init` instead.
350 pub fn read5<'a, G1: Arg + Get<'a>, G2: Arg + Get<'a>, G3: Arg + Get<'a>, G4: Arg + Get<'a>, G5: Arg + Get<'a>>(&'a self) ->
351 Result<(G1, G2, G3, G4, G5), TypeMismatchError> {
352 let mut i = Iter::new(&self);
353 Ok((i.read()?, i.read()?, i.read()?, i.read()?, i.read()?))
354 }
355
356 /// Gets arguments from a message.
357 ///
358 /// If this was an error reply or if types mismatch, an error is returned.
359 pub fn read_all<R: ReadAll>(&self) -> Result<R, Error> {
360 self.set_error_from_msg()?;
361 Ok(R::read(&mut self.iter_init())?)
362 }
363
364 /// Returns a struct for retreiving the arguments from a message. Supersedes get_items().
365 pub fn iter_init(&self) -> Iter { Iter::new(&self) }
366
367 /// Gets the MessageType of the Message.
368 pub fn msg_type(&self) -> MessageType {
369 match unsafe { ffi::dbus_message_get_type(self.msg) } {
370 1 => MessageType::MethodCall,
371 2 => MessageType::MethodReturn,
372 3 => MessageType::Error,
373 4 => MessageType::Signal,
374 x => panic!("Invalid message type {}", x),
375 }
376 }
377
378 fn msg_internal_str<'a>(&'a self, c: *const libc::c_char) -> Option<&'a str> {
379 if c.is_null() { return None };
380 let cc = unsafe { CStr::from_ptr(c) };
381 std::str::from_utf8(cc.to_bytes_with_nul()).ok()
382 }
383
384 /// Gets the name of the connection that originated this message.
385 pub fn sender(&self) -> Option<BusName> {
386 self.msg_internal_str(unsafe { ffi::dbus_message_get_sender(self.msg) })
387 .map(|s| unsafe { BusName::from_slice_unchecked(s) })
388 }
389
390 /// Gets the object path this Message is being sent to.
391 pub fn path(&self) -> Option<Path> {
392 self.msg_internal_str(unsafe { ffi::dbus_message_get_path(self.msg) })
393 .map(|s| unsafe { Path::from_slice_unchecked(s) })
394 }
395
396 /// Gets the destination this Message is being sent to.
397 pub fn destination(&self) -> Option<BusName> {
398 self.msg_internal_str(unsafe { ffi::dbus_message_get_destination(self.msg) })
399 .map(|s| unsafe { BusName::from_slice_unchecked(s) })
400 }
401
402 /// Sets the destination of this Message
403 ///
404 /// If dest is none, that means broadcast to all relevant destinations.
405 pub fn set_destination(&mut self, dest: Option<BusName>) {
406 let c_dest = dest.as_ref().map(|d| d.as_cstr().as_ptr()).unwrap_or(ptr::null());
407 assert!(unsafe { ffi::dbus_message_set_destination(self.msg, c_dest) } != 0);
408 }
409
410 /// Gets the interface this Message is being sent to.
411 pub fn interface(&self) -> Option<Interface> {
412 self.msg_internal_str(unsafe { ffi::dbus_message_get_interface(self.msg) })
413 .map(|s| unsafe { Interface::from_slice_unchecked(s) })
414 }
415
416 /// Gets the interface member being called.
417 pub fn member(&self) -> Option<Member> {
418 self.msg_internal_str(unsafe { ffi::dbus_message_get_member(self.msg) })
419 .map(|s| unsafe { Member::from_slice_unchecked(s) })
420 }
421
422 /// When the remote end returns an error, the message itself is
423 /// correct but its contents is an error. This method will
424 /// transform such an error to a D-Bus Error or otherwise return
425 /// the original message.
426 pub fn as_result(&mut self) -> Result<&mut Message, Error> {
427 self.set_error_from_msg().map(|_| self)
428 }
429
430 pub (crate) fn set_error_from_msg(&self) -> Result<(), Error> {
431 let mut e = Error::empty();
432 if unsafe { ffi::dbus_set_error_from_message(e.get_mut(), self.msg) } != 0 { Err(e) }
433 else { Ok(()) }
434 }
435
436 pub (crate) fn ptr(&self) -> *mut ffi::DBusMessage { self.msg }
437
438 pub (crate) fn from_ptr(ptr: *mut ffi::DBusMessage, add_ref: bool) -> Message {
439 if add_ref {
440 unsafe { ffi::dbus_message_ref(ptr) };
441 }
442 Message { msg: ptr }
443 }
444
445 /// Sets serial number manually - mostly for internal use
446 ///
447 /// When sending a message, a serial will be automatically assigned, so you don't need to call
448 /// this method. However, it can be very useful in test code that is supposed to handle a method call.
449 /// This way, you can create a method call and handle it without sending it to a real D-Bus instance.
450 pub fn set_serial(&mut self, val: u32) {
451 unsafe { ffi::dbus_message_set_serial(self.msg, val) };
452 }
453
454 /// Marshals a message - mostly for internal use
455 ///
456 /// The function f will be called one or more times with bytes to be written somewhere.
457 /// You should call set_serial to manually set a serial number before calling this function
458 pub fn marshal<E, F: FnMut(&[u8]) -> Result<(), E>>(&self, mut f: F) -> Result<(), E> {
459 let mut len = 0;
460 let mut data = ptr::null_mut();
461 if unsafe { ffi::dbus_message_marshal(self.msg, &mut data, &mut len) } == 0 {
462 panic!("out of memory");
463 }
464 let s = unsafe { std::slice::from_raw_parts(data as *mut u8 as *const u8, len as usize) };
465 let r = f(s);
466 unsafe { ffi::dbus_free(data as *mut _) };
467 r
468 }
469
470 /// Demarshals a message - mostly for internal use
471 pub fn demarshal(data: &[u8]) -> Result<Self, Error> {
472 let mut e = Error::empty();
473 let p = unsafe { ffi::dbus_message_demarshal(data.as_ptr() as *const _, data.len() as _, e.get_mut()) };
474 if p == ptr::null_mut() {
475 Err(e)
476 } else {
477 Ok(Self::from_ptr(p, false))
478 }
479 }
480
481 /// Returns the size of the message - mostly for internal use
482 ///
483 /// Returns Err(()) on protocol errors. Make sure you have at least 16 bytes in the buffer
484 /// before calling this method.
485 pub fn demarshal_bytes_needed(data: &[u8]) -> Result<usize, ()> {
486 const MIN_HEADER: usize = 16;
487 if data.len() < MIN_HEADER { return Ok(MIN_HEADER); }
488 let x = unsafe { ffi::dbus_message_demarshal_bytes_needed(data.as_ptr() as *const _, data.len() as _) };
489 if x < MIN_HEADER as _ { Err(()) } else { Ok(x as usize) }
490 }
491
492}
493
494impl Drop for Message {
495 fn drop(&mut self) {
496 unsafe {
497 ffi::dbus_message_unref(self.msg);
498 }
499 }
500}
501
502impl fmt::Debug for Message {
503 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
504 let mut x: DebugStruct<'_, '_> = f.debug_struct(name:"Message");
505 x.field(name:"Type", &self.msg_type());
506 // The &&** derefs to a &&str, which implements &dyn Debug
507 if let Some(ref path: &Path<'_>) = self.path() { x.field(name:"Path", &&**path); }
508 if let Some(ref iface: &Interface<'_>) = self.interface() { x.field(name:"Interface", &&**iface); }
509 if let Some(ref member: &Member<'_>) = self.member() { x.field(name:"Member", &&**member); }
510 if let Some(ref sender: &BusName<'_>) = self.sender() { x.field(name:"Sender", &&**sender); }
511 if let Some(ref dest: &BusName<'_>) = self.destination() { x.field(name:"Destination", &&**dest); }
512 if let Some(ref serial: &u32) = self.get_serial() { x.field(name:"Serial", value:serial); }
513 if let Some(ref rs: &u32) = self.get_reply_serial() { x.field(name:"ReplySerial", value:rs); }
514 let mut args: Vec> = vec!();
515 let mut iter: Iter<'_> = self.iter_init();
516 while let Some(a: Box) = iter.get_refarg() {
517 args.push(a);
518 iter.next();
519 }
520 let args2: &[_] = &args;
521 x.field(name:"Args", &args2);
522 x.finish()
523 }
524}
525
526#[cfg(test)]
527mod test {
528 use crate::{Message};
529 use crate::strings::BusName;
530
531 #[test]
532 fn set_valid_destination() {
533 let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap();
534 let d = Some(BusName::new(":1.14").unwrap());
535 m.set_destination(d);
536
537 assert!(!m.get_no_reply());
538 m.set_no_reply(true);
539 assert!(m.get_no_reply());
540 }
541
542 #[test]
543 fn marshal() {
544 let mut m = Message::new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "Hello").unwrap();
545 m.set_serial(1);
546 let r = m.marshal(|d| {
547 let m2 = Message::demarshal(d).unwrap();
548 assert_eq!(&*m2.path().unwrap(), "/org/freedesktop/DBus");
549 Err(45)
550 });
551 assert_eq!(45, r.unwrap_err());
552 }
553}
554