dbus_message_parser/message/
message_struct.rs

1use crate::{
2    message::{
3        header::{Header, HeaderFields},
4        MessageFlags, MessageType,
5    },
6    value::{Bus, Error, Interface, Member, ObjectPath, Type, TypeError, Value},
7};
8use std::convert::TryInto;
9
10macro_rules! get_field {
11    ($(#[$meta:meta])* $function:ident, $return:ty) => {
12        $(#[$meta])*
13        #[inline]
14        pub const fn $function(&self) -> Option<$return> {
15            self.header.$function()
16        }
17    };
18}
19
20macro_rules! has_field {
21    ($(#[$meta:meta])* $function:ident) => {
22        $(#[$meta])*
23        #[inline]
24        pub const fn $function(&self) -> bool {
25            self.header.$function()
26        }
27    };
28}
29
30/// This represents a DBus [message].
31///
32/// [message]: https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol
33#[derive(Debug, Clone, PartialOrd, PartialEq)]
34pub struct Message {
35    pub(crate) header: Header,
36    pub(crate) body: Vec<Value>,
37}
38
39impl Message {
40    /// Create a [`Message`] object.
41    pub fn new(header: Header, body: Vec<Value>) -> Message {
42        Message { header, body }
43    }
44
45    /// Create a [`Message`] object as a [`MethodCall`].
46    ///
47    /// [`MethodCall`]: crate::message::MessageType::MethodCall
48    pub fn method_call(
49        destination: Bus,
50        object_path: ObjectPath,
51        interface: Interface,
52        member: Member,
53    ) -> Message {
54        let fields = HeaderFields {
55            destination: Some(destination),
56            path: Some(object_path),
57            interface: Some(interface),
58            member: Some(member),
59            ..Default::default()
60        };
61
62        let header = Header {
63            is_le: true,
64            message_type: MessageType::MethodCall,
65            message_flags: MessageFlags::empty(),
66            version: 1,
67            serial: 0,
68            fields,
69        };
70        Message {
71            header,
72            body: Vec::new(),
73        }
74    }
75
76    /// Create a [`Message`] object as a [`Signal`].
77    ///
78    /// [`Signal`]: crate::message::MessageType::Signal
79    pub fn signal(object_path: ObjectPath, interface: Interface, member: Member) -> Message {
80        let fields = HeaderFields {
81            path: Some(object_path),
82            interface: Some(interface),
83            member: Some(member),
84            ..Default::default()
85        };
86
87        let header = Header {
88            is_le: true,
89            message_type: MessageType::Signal,
90            message_flags: MessageFlags::NO_REPLY_EXPECTED,
91            version: 1,
92            serial: 0,
93            fields,
94        };
95        Message {
96            header,
97            body: Vec::new(),
98        }
99    }
100
101    /// Create a [`Message`] to retrieve property value.
102    pub fn property_get(
103        destination: Bus,
104        object_path: ObjectPath,
105        interface: Interface,
106        property: &str,
107    ) -> Message {
108        let mut msg = Message::method_call(
109            destination,
110            object_path,
111            "org.freedesktop.DBus.Properties".try_into().unwrap(),
112            "Get".try_into().unwrap(),
113        );
114
115        msg.add_value(Value::String(interface.to_string()));
116        msg.add_value(Value::String(property.to_string()));
117
118        msg
119    }
120
121    /// Create a [`Message`] to retrieve property value.
122    pub fn properties_get_all(
123        destination: Bus,
124        object_path: ObjectPath,
125        interface: Interface,
126    ) -> Message {
127        let mut msg = Message::method_call(
128            destination,
129            object_path,
130            "org.freedesktop.DBus.Properties".try_into().unwrap(),
131            "GetAll".try_into().unwrap(),
132        );
133
134        msg.add_value(Value::String(interface.to_string()));
135
136        msg
137    }
138
139    /// Create a [`Message`] to retrieve property value.
140    pub fn property_set(
141        destination: Bus,
142        object_path: ObjectPath,
143        interface: Interface,
144        property: &str,
145        value: Value,
146    ) -> Message {
147        let mut msg = Message::method_call(
148            destination,
149            object_path,
150            "org.freedesktop.DBus.Properties".try_into().unwrap(),
151            "Set".try_into().unwrap(),
152        );
153
154        msg.add_value(Value::String(interface.to_string()));
155        msg.add_value(Value::String(property.to_string()));
156        msg.add_value(Value::Variant(Box::new(value)));
157
158        msg
159    }
160
161    /// Get the serial number.
162    #[inline]
163    pub const fn get_serial(&self) -> u32 {
164        self.header.get_serial()
165    }
166
167    /// Set the serial number.
168    #[inline]
169    pub fn set_serial(&mut self, serial: u32) {
170        self.header.serial = serial;
171    }
172
173    get_field!(
174        /// Get the [`path`], if there is one in the header field.
175        ///
176        /// [`path`]: crate::message::MessageHeaderFields::path
177        get_path,
178        &ObjectPath
179    );
180
181    has_field!(
182        /// It is true if the message contains a [`path`] in the header fields.
183        ///
184        /// [`path`]: crate::message::MessageHeaderField::path
185        has_path
186    );
187
188    get_field!(
189        /// Get the [`interface`], if there is one in the header field.
190        ///
191        /// [`interface`]: crate::message::MessageHeaderFields::interface
192        get_interface,
193        &Interface
194    );
195
196    has_field!(
197        /// It is true if the message contains an [`interface`] in the header fields.
198        ///
199        /// [`interface`]: crate::message::MessageHeaderFields::interface
200        has_interface
201    );
202
203    get_field!(
204        /// Get the [`member`], if there is one in the header field.
205        ///
206        /// [`member`]: crate::message::MessageHeaderFields::member
207        get_member,
208        &Member
209    );
210
211    has_field!(
212        /// It is true if the message contains a [`member`] in the header fields.
213        ///
214        /// [`member`]: crate::message::MessageHeaderFields::member
215        has_member
216    );
217
218    get_field!(
219        /// Get the [`error_name`], if there is one in the header field.
220        ///
221        /// [`error_name`]: crate::message::MessageHeaderFields::error_name
222        get_error_name,
223        &Error
224    );
225
226    has_field!(
227        /// It is true if the message contains an [`error_name`] in the header fields.
228        ///
229        /// [`error_name`]: crate::message::MessageHeaderFields::error_name
230        has_error_name
231    );
232
233    get_field!(
234        /// Get the [`destination`], if there is one in the header field.
235        ///
236        /// [`destination`]: crate::message::MessageHeaderFields::destination
237        get_destination,
238        &Bus
239    );
240
241    has_field!(
242        /// It is true if the message contains a [`destination`] in the header fields.
243        ///
244        /// [`destination`]: crate::message::MessageHeaderFields::destination
245        has_destination
246    );
247
248    get_field!(
249        /// Get the [`sender`], if there is one in the header field.
250        ///
251        /// [`sender`]: crate::message::MessageHeaderFields::sender
252        get_sender,
253        &Bus
254    );
255
256    has_field!(
257        /// It is true if the message contains a [`sender`] in the header fields.
258        ///
259        /// [`sender`]: crate::message::MessageHeaderFields::sender
260        has_sender
261    );
262
263    get_field!(
264        /// Get the [`reply_serial`], if there is one in the header field.
265        ///
266        /// [`reply_serial`]: crate::message::MessageHeaderFields::reply_serial
267        get_reply_serial,
268        u32
269    );
270
271    has_field!(
272        /// It is true if the message contains a [`reply_serial`] in the header fields.
273        ///
274        /// [`reply_serial`]: crate::message::MessageHeaderFields::reply_serial
275        has_reply_serial
276    );
277
278    /// Get the [`signature`], if there is one in the header field.
279    ///
280    /// [`signature`]: crate::message::MessageHeaderFields::signature
281    pub fn get_signature(&self) -> Result<Vec<Type>, TypeError> {
282        let mut signature = Vec::new();
283        for value in &self.body {
284            let type_ = value.get_type()?;
285            signature.push(type_);
286        }
287
288        Ok(signature)
289    }
290
291    has_field!(
292        /// It is true if the message contains a [`signature`] in the header fields.
293        ///
294        /// [`signature`]: crate::message::MessageHeaderFields::signature
295        has_signature
296    );
297
298    #[cfg(target_family = "unix")]
299    get_field!(
300        /// Get the [`unix_fds`], if there is one in the header field.
301        ///
302        /// [`unix_fds`]: crate::message::MessageHeaderFields::unix_fds
303        get_unix_fds,
304        u32
305    );
306
307    #[cfg(target_family = "unix")]
308    has_field!(
309        /// It is true if the message contains a [`unix_fds`] in the header fields.
310        ///
311        /// [`unix_fds`]: crate::message::MessageHeaderFields::unix_fds
312        has_unix_fds
313    );
314
315    /// Add a new value to the body.
316    pub fn add_value(&mut self, value: Value) {
317        self.body.push(value);
318    }
319
320    /// Create a message return from this [`Message`].
321    /// Only works if this [`Message`] is a [`MethodCall`].
322    ///
323    /// [`MethodCall`]: crate::message::MessageType::MethodCall
324    pub fn method_return(&self) -> Result<Message, Message> {
325        self.header.method_return()
326    }
327
328    /// Create a unknown property error message from this [`Message`].
329    pub fn unknown_property(&self, property: &str) -> Message {
330        self.header.unknown_property(property)
331    }
332
333    /// Create a unknown path error message from this [`Message`].
334    pub fn unknown_path(&self) -> Option<Message> {
335        self.header.unknown_path()
336    }
337
338    /// Create a unknown interface error message from this [`Message`].
339    pub fn unknown_interface(&self) -> Option<Message> {
340        self.header.unknown_interface()
341    }
342
343    /// Create a unknown member error message from this [`Message`].
344    pub fn unknown_member(&self) -> Option<Message> {
345        self.header.unknown_member()
346    }
347
348    /// Create an invalid args error message from this [`Message`].
349    pub fn invalid_args(&self, reason: String) -> Message {
350        self.header.invalid_args(reason)
351    }
352
353    /// Create an error message from this [`Message`].
354    pub fn error(&self, name: Error, message: String) -> Message {
355        self.header.error(name, message)
356    }
357
358    /// Get the body.
359    #[inline]
360    pub fn get_body(&self) -> &[Value] {
361        &self.body
362    }
363
364    /// Get the message type.
365    #[inline]
366    pub fn get_type(&self) -> MessageType {
367        self.header.get_type()
368    }
369
370    /// Split the [`Message`] object into the header and the body.
371    pub fn split(mut self) -> Result<(Header, Vec<Value>), TypeError> {
372        let signature = self.get_signature()?;
373        if !signature.is_empty() {
374            self.header.fields.signature = Some(signature);
375        }
376        Ok((self.header, self.body))
377    }
378}