Skip to main content

tokio_dbus/message/
message.rs

1#[cfg(feature = "alloc")]
2use alloc::boxed::Box;
3
4use crate::proto::{Flags, MessageType};
5use crate::{AsBody, Body, MessageKind, ObjectPath, Serial, Signature};
6
7#[cfg(feature = "alloc")]
8use crate::{BodyBuf, MessageBuf};
9
10/// A borrowed D-Bus message.
11///
12/// This is the borrowed variant of [`MessageBuf`], to convert to an
13/// [`MessageBuf`], use [`Message::to_owned`].
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct Message<'a> {
16    /// The type of the message.
17    pub(crate) kind: MessageKind<'a>,
18    /// Serial of the emssage.
19    pub(crate) serial: Serial,
20    /// Flags in the message.
21    pub(crate) flags: Flags,
22    /// The interface of the message.
23    pub(crate) interface: Option<&'a str>,
24    /// The destination of the message.
25    pub(crate) destination: Option<&'a str>,
26    /// The sender of the message.
27    pub(crate) sender: Option<&'a str>,
28    /// The body associated with the message.
29    pub(crate) body: Body<'a>,
30}
31
32impl<'a> Message<'a> {
33    /// Construct a method call [`Message`].
34    ///
35    /// # Examples
36    ///
37    /// ```
38    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
39    ///
40    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
41    ///
42    /// let mut send = SendBuf::new();
43    ///
44    /// let m = send.method_call(PATH, "Hello");
45    /// let m2 = Message::method_call(PATH, "Hello", m.serial());
46    /// assert_eq!(m, m2);
47    /// ```
48    pub fn method_call(path: &'a ObjectPath, member: &'a str, serial: Serial) -> Self {
49        Self {
50            kind: MessageKind::MethodCall { path, member },
51            serial,
52            flags: Flags::EMPTY,
53            interface: None,
54            destination: None,
55            sender: None,
56            body: Body::empty(),
57        }
58    }
59
60    /// Convert this message into a [`MessageKind::MethodReturn`] message with
61    /// an empty body where the reply serial matches that of the current
62    /// message.
63    ///
64    /// The `send` argument is used to populate the next serial number.
65    ///
66    /// # Examples
67    ///
68    /// ```
69    /// use tokio_dbus::{Message, MessageKind, ObjectPath, SendBuf};
70    ///
71    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
72    ///
73    /// let mut send = SendBuf::new();
74    ///
75    /// let m = send.method_call(PATH, "Hello")
76    ///     .with_sender("se.tedro.DBusExample")
77    ///     .with_destination("org.freedesktop.DBus");
78    ///
79    /// let m2 = m.method_return(send.next_serial());
80    /// assert!(matches!(m2.kind(), MessageKind::MethodReturn { .. }));
81    ///
82    /// assert_eq!(m.sender(), m2.destination());
83    /// assert_eq!(m.destination(), m2.sender());
84    /// ```
85    pub fn method_return(&self, serial: Serial) -> Self {
86        Self {
87            kind: MessageKind::MethodReturn {
88                reply_serial: self.serial,
89            },
90            serial,
91            flags: Flags::EMPTY,
92            interface: None,
93            destination: self.sender,
94            sender: self.destination,
95            body: Body::empty(),
96        }
97    }
98
99    /// Construct a signal [`Message`].
100    ///
101    /// A signal is emitted from an object, so it carries the path of the object
102    /// which emitted it.
103    ///
104    /// # Examples
105    ///
106    /// ```
107    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
108    ///
109    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
110    ///
111    /// let mut send = SendBuf::new();
112    ///
113    /// let m = send.signal(PATH, "Hello");
114    /// let m2 = Message::signal(PATH, "Hello", m.serial());
115    /// assert_eq!(m, m2);
116    /// ```
117    #[must_use]
118    pub fn signal(path: &'a ObjectPath, member: &'a str, serial: Serial) -> Self {
119        Self {
120            kind: MessageKind::Signal { path, member },
121            serial,
122            flags: Flags::EMPTY,
123            interface: None,
124            destination: None,
125            sender: None,
126            body: Body::empty(),
127        }
128    }
129
130    /// Convert this message into a [`MessageKind::Error`] message with
131    /// an empty body where the reply serial matches that of the current
132    /// message.
133    ///
134    /// # Examples
135    ///
136    /// ```
137    /// use tokio_dbus::{Message, MessageKind, ObjectPath, SendBuf};
138    ///
139    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
140    ///
141    /// let mut send = SendBuf::new();
142    ///
143    /// let m = send.method_call(PATH, "Hello")
144    ///     .with_sender("se.tedro.DBusExample")
145    ///     .with_destination("org.freedesktop.DBus");
146    ///
147    /// let m2 = m.error("org.freedesktop.DBus.UnknownMethod", send.next_serial());
148    /// assert!(matches!(m2.kind(), MessageKind::Error { .. }));
149    ///
150    /// assert_eq!(m.sender(), m2.destination());
151    /// assert_eq!(m.destination(), m2.sender());
152    /// ```
153    #[must_use]
154    pub fn error(&self, error_name: &'a str, serial: Serial) -> Self {
155        Self {
156            kind: MessageKind::Error {
157                error_name,
158                reply_serial: self.serial,
159            },
160            serial,
161            flags: Flags::EMPTY,
162            interface: None,
163            destination: self.sender,
164            sender: self.destination,
165            body: Body::empty(),
166        }
167    }
168
169    /// Convert into an owned [`MessageBuf`].
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// use tokio_dbus::{Message, MessageBuf, ObjectPath, SendBuf};
175    ///
176    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
177    ///
178    /// let mut send = SendBuf::new();
179    ///
180    /// let m = send.method_call(PATH, "Hello").to_owned();
181    /// let m2 = MessageBuf::method_call(PATH.into(), "Hello".into(), m.serial());
182    /// assert_eq!(m, m2);
183    /// ```
184    #[inline]
185    #[cfg(feature = "alloc")]
186    pub fn to_owned(&self) -> MessageBuf {
187        MessageBuf {
188            kind: self.kind.to_owned(),
189            serial: self.serial,
190            flags: self.flags,
191            interface: self.interface.map(Box::from),
192            destination: self.destination.map(Box::from),
193            sender: self.sender.map(Box::from),
194            body: BodyBuf::from(self.body.clone()),
195        }
196    }
197
198    /// Get the kind of the message.
199    ///
200    /// # Examples
201    ///
202    /// ```
203    /// use tokio_dbus::{Message, MessageKind, ObjectPath, SendBuf};
204    ///
205    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
206    ///
207    /// let mut send = SendBuf::new();
208    ///
209    /// let m = send.method_call(PATH, "Hello");
210    /// assert!(matches!(m.kind(), MessageKind::MethodCall { .. }));
211    ///
212    /// let m2 = m.error("org.freedesktop.DBus.UnknownMethod", send.next_serial());
213    /// assert!(matches!(m2.kind(), MessageKind::Error { .. }));
214    /// ```
215    #[must_use]
216    pub fn kind(&self) -> MessageKind<'a> {
217        self.kind
218    }
219
220    /// Modify the body and signature of the message to match that of the
221    /// provided body buffer.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use tokio_dbus::{BodyBuf, MessageKind, ObjectPath, SendBuf, Signature};
227    ///
228    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
229    ///
230    /// let mut send = SendBuf::new();
231    /// let mut body = BodyBuf::new();
232    ///
233    /// body.store("Hello World!");
234    ///
235    /// let m = send.method_call(PATH, "Hello")
236    ///     .with_body(&body);
237    ///
238    /// assert!(matches!(m.kind(), MessageKind::MethodCall { .. }));
239    /// assert_eq!(m.signature(), Signature::STRING);
240    /// ```
241    #[must_use]
242    pub fn with_body(self, body: impl AsBody<'a>) -> Self {
243        Self {
244            body: body.as_body(),
245            ..self
246        }
247    }
248
249    /// Get a buffer to the body of the message.
250    ///
251    /// # Examples
252    ///
253    /// ```
254    /// use tokio_dbus::{BodyBuf, MessageKind, ObjectPath, SendBuf};
255    ///
256    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
257    ///
258    /// let mut send = SendBuf::new();
259    /// let mut body = BodyBuf::new();
260    ///
261    /// body.store(42u32);
262    /// body.store("Hello World!");
263    ///
264    /// let m = send.method_call(PATH, "Hello")
265    ///     .with_body(&body);
266    ///
267    /// assert!(matches!(m.kind(), MessageKind::MethodCall { .. }));
268    /// assert_eq!(m.signature(), "us");
269    ///
270    /// let mut r = m.body();
271    /// assert_eq!(r.load::<u32>()?, 42);
272    /// assert_eq!(r.read::<str>()?, "Hello World!");
273    /// # Ok::<_, tokio_dbus::Error>(())
274    /// ```
275    #[must_use]
276    pub fn body(&self) -> Body<'a> {
277        self.body.clone()
278    }
279
280    /// Get the serial of the message.
281    ///
282    /// # Examples
283    ///
284    /// ```
285    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
286    ///
287    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
288    ///
289    /// let mut send = SendBuf::new();
290    ///
291    /// let m = send.method_call(PATH, "Hello");
292    /// let initial = m.serial();
293    /// let serial = send.next_serial();
294    /// let m2 = m.with_serial(serial);
295    ///
296    /// assert_eq!(m2.serial(), serial);
297    /// assert_ne!(m2.serial(), initial);
298    /// ```
299    #[inline]
300    pub fn serial(&self) -> Serial {
301        self.serial
302    }
303
304    /// Modify the serial of the message.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
310    ///
311    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
312    ///
313    /// let mut send = SendBuf::new();
314    ///
315    /// let m = send.method_call(PATH, "Hello");
316    /// let serial = send.next_serial();
317    /// let initial = m.serial();
318    /// let m = m.with_serial(serial);
319    ///
320    /// assert_eq!(m.serial(), serial);
321    /// assert_ne!(m.serial(), initial);
322    /// ```
323    #[must_use]
324    pub fn with_serial(self, serial: Serial) -> Self {
325        Self { serial, ..self }
326    }
327
328    /// Get the flags of the message.
329    ///
330    /// # Examples
331    ///
332    /// ```
333    /// use tokio_dbus::{Flags, Message, ObjectPath, SendBuf};
334    ///
335    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
336    ///
337    /// let mut send = SendBuf::new();
338    ///
339    /// let m = send.method_call(PATH, "Hello");
340    /// assert_eq!(m.flags(), Flags::default());
341    ///
342    /// let m2 = m.with_flags(Flags::NO_REPLY_EXPECTED);
343    /// assert_eq!(m2.flags(), Flags::NO_REPLY_EXPECTED);
344    /// ```
345    #[must_use]
346    pub fn flags(&self) -> Flags {
347        self.flags
348    }
349
350    /// Modify the flags of the message.
351    ///
352    /// # Examples
353    ///
354    /// ```
355    /// use tokio_dbus::{Flags, Message, ObjectPath, SendBuf};
356    ///
357    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
358    ///
359    /// let mut send = SendBuf::new();
360    ///
361    /// let m = send.method_call(PATH, "Hello");
362    /// assert_eq!(m.flags(), Flags::default());
363    ///
364    /// let m2 = m.with_flags(Flags::NO_REPLY_EXPECTED);
365    /// assert_eq!(m2.flags(), Flags::NO_REPLY_EXPECTED);
366    /// ```
367    #[must_use]
368    pub fn with_flags(self, flags: Flags) -> Self {
369        Self { flags, ..self }
370    }
371
372    /// Get the interface of the message.
373    ///
374    /// # Examples
375    ///
376    /// ```
377    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
378    ///
379    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
380    ///
381    /// let mut send = SendBuf::new();
382    ///
383    /// let m = send.method_call(PATH, "Hello");
384    /// assert_eq!(m.interface(), None);
385    ///
386    /// let m2 = m.with_interface("org.freedesktop.DBus");
387    /// assert_eq!(m2.interface(), Some("org.freedesktop.DBus"));
388    /// ```
389    #[must_use]
390    pub fn interface(&self) -> Option<&'a str> {
391        self.interface
392    }
393
394    /// Modify the interface of the message.
395    ///
396    /// # Examples
397    ///
398    /// ```
399    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
400    ///
401    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
402    ///
403    /// let mut send = SendBuf::new();
404    ///
405    /// let m = send.method_call(PATH, "Hello");
406    /// assert_eq!(m.interface(), None);
407    ///
408    /// let m2 = m.with_interface("org.freedesktop.DBus");
409    /// assert_eq!(m2.interface(), Some("org.freedesktop.DBus"));
410    /// ```
411    #[must_use]
412    pub fn with_interface(self, interface: &'a str) -> Self {
413        Self {
414            interface: Some(interface),
415            ..self
416        }
417    }
418
419    /// Get the destination of the message.
420    ///
421    /// # Examples
422    ///
423    /// ```
424    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
425    ///
426    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
427    ///
428    /// let mut send = SendBuf::new();
429    ///
430    /// let m = send.method_call(PATH, "Hello");
431    /// assert_eq!(m.destination(), None);
432    ///
433    /// let m2 = m.with_destination(":1.131");
434    /// assert_eq!(m2.destination(), Some(":1.131"));
435    /// ```
436    #[must_use]
437    pub fn destination(&self) -> Option<&'a str> {
438        self.destination
439    }
440
441    /// Modify the destination of the message.
442    ///
443    /// # Examples
444    ///
445    /// ```
446    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
447    ///
448    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
449    ///
450    /// let mut send = SendBuf::new();
451    ///
452    /// let m = send.method_call(PATH, "Hello");
453    /// assert_eq!(m.destination(), None);
454    ///
455    /// let m2 = m.with_destination(":1.131");
456    /// assert_eq!(m2.destination(), Some(":1.131"));
457    /// ```
458    #[must_use]
459    pub fn with_destination(self, destination: &'a str) -> Self {
460        Self {
461            destination: Some(destination),
462            ..self
463        }
464    }
465
466    /// Get the sender of the message.
467    ///
468    /// # Examples
469    ///
470    /// ```
471    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
472    ///
473    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
474    ///
475    /// let mut send = SendBuf::new();
476    ///
477    /// let m = send.method_call(PATH, "Hello");
478    /// assert_eq!(m.destination(), None);
479    ///
480    /// let m2 = m.with_sender(":1.131");
481    /// assert_eq!(m2.sender(), Some(":1.131"));
482    /// ```
483    #[must_use]
484    pub fn sender(&self) -> Option<&'a str> {
485        self.sender
486    }
487
488    /// Modify the sender of the message.
489    ///
490    /// # Examples
491    ///
492    /// ```
493    /// use tokio_dbus::{Message, ObjectPath, SendBuf};
494    ///
495    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
496    ///
497    /// let mut send = SendBuf::new();
498    ///
499    /// let m = send.method_call(PATH, "Hello");
500    /// assert_eq!(m.destination(), None);
501    ///
502    /// let m2 = m.with_sender(":1.131");
503    /// assert_eq!(m2.sender(), Some(":1.131"));
504    /// ```
505    #[must_use]
506    pub fn with_sender(self, sender: &'a str) -> Self {
507        Self {
508            sender: Some(sender),
509            ..self
510        }
511    }
512
513    /// Get the signature of the message.
514    ///
515    /// # Examples
516    ///
517    /// ```
518    /// use tokio_dbus::{BodyBuf, ObjectPath, SendBuf, Signature};
519    ///
520    /// const PATH: &ObjectPath = ObjectPath::new_const(b"/org/freedesktop/DBus");
521    ///
522    /// let mut send = SendBuf::new();
523    ///
524    /// let m = send.method_call(PATH, "Hello");
525    /// assert_eq!(m.signature(), Signature::EMPTY);
526    ///
527    /// let mut body = BodyBuf::new();
528    /// body.store("Hello World!");
529    ///
530    /// let m2 = m.with_body(&body);
531    /// assert_eq!(m2.signature(), Signature::STRING);
532    /// ```
533    #[must_use]
534    pub fn signature(&self) -> &Signature {
535        self.body.signature()
536    }
537
538    #[cfg(feature = "alloc")]
539    pub(crate) fn message_type(&self) -> crate::proto::MessageType {
540        match self.kind {
541            MessageKind::MethodCall { .. } => MessageType::METHOD_CALL,
542            MessageKind::MethodReturn { .. } => MessageType::METHOD_RETURN,
543            MessageKind::Error { .. } => MessageType::ERROR,
544            MessageKind::Signal { .. } => MessageType::SIGNAL,
545        }
546    }
547}
548
549#[cfg(feature = "alloc")]
550impl PartialEq<MessageBuf> for Message<'_> {
551    #[inline]
552    fn eq(&self, other: &MessageBuf) -> bool {
553        self.kind == other.kind
554            && self.serial == other.serial
555            && self.flags == other.flags
556            && self.interface == other.interface.as_deref()
557            && self.destination == other.destination.as_deref()
558            && self.sender == other.sender.as_deref()
559            && self.body == other.body
560    }
561}