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}