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}