tokio_dbus/message/
message.rs

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