1 //! Types and traits for easily getting a message's arguments, or appening a message with arguments.
2 //!
3 //! Also see the arguments guide (in the examples directory).
4 //!
5 //! A message has `read1`, `read2` etc, and `append1`, `append2` etc, which is your
6 //! starting point into this module's types.
7 //!
8 //! **Append a**:
9 //!
10 //! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type
11 //!
12 //! `&str` - a D-Bus string. D-Bus strings do not allow null characters, so
13 //! if the string contains null characters, it will be cropped
14 //! to only include the data before the null character. (Tip: This allows for skipping an
15 //! allocation by writing a string literal which ends with a null character.)
16 //!
17 //! `&[T] where T: Append` - a D-Bus array. Note: can use an efficient fast-path in case of
18 //! T being an FixedArray type.
19 //!
20 //! `Array<T, I> where T: Append, I: Iterator<Item=T>` - a D-Bus array, maximum flexibility.
21 //!
22 //! `Variant<T> where T: Append` - a D-Bus variant.
23 //!
24 //! `(T1, T2) where T1: Append, T2: Append` - tuples are D-Bus structs. Implemented up to 12.
25 //!
26 //! `Dict<K, V, I> where K: Append + DictKey, V: Append, I: Iterator<Item=(&K, &V)>` - A D-Bus dict (array of dict entries).
27 //!
28 //! `Path` - a D-Bus object path.
29 //!
30 //! `Signature` - a D-Bus signature.
31 //!
32 //! `OwnedFd` - shares the file descriptor with the remote side.
33 //!
34 //! **Get / read a**:
35 //!
36 //! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type
37 //!
38 //! `&str`, `&CStr` - a D-Bus string. D-Bus strings are always UTF-8 and do not contain null characters.
39 //!
40 //! `&[T] where T: FixedArray` - a D-Bus array of integers or f64.
41 //!
42 //! `Array<T, Iter> where T: Get` - a D-Bus array, maximum flexibility. Implements Iterator so you can easily
43 //! collect it into, e g, a `Vec`.
44 //!
45 //! `Variant<T> where T: Get` - a D-Bus variant. Use this type of Variant if you know the inner type.
46 //!
47 //! `Variant<Iter>` - a D-Bus variant. This type of Variant allows you to examine the inner type.
48 //!
49 //! `(T1, T2) where T1: Get, T2: Get` - tuples are D-Bus structs. Implemented up to 12.
50 //!
51 //! `Dict<K, V, Iter> where K: Get + DictKey, V: Get` - A D-Bus dict (array of dict entries). Implements Iterator so you can easily
52 //! collect it into, e g, a `HashMap`.
53 //!
54 //! `Path` - a D-Bus object path.
55 //!
56 //! `Signature` - a D-Bus signature.
57 //!
58 //! `OwnedFd` - a file descriptor sent from the remote side.
59 //!
60 
61 mod msgarg;
62 mod basic_impl;
63 mod variantstruct_impl;
64 mod array_impl;
65 
66 pub use self::msgarg::{Arg, FixedArray, Get, DictKey, Append, RefArg, cast, cast_mut};
67 pub use self::array_impl::{Array, Dict};
68 pub use self::variantstruct_impl::Variant;
69 
70 use std::{fmt, mem, ptr, error};
71 use {ffi, Message, message, Signature, Path, OwnedFd};
72 use std::ffi::{CStr, CString};
73 use std::os::raw::{c_void, c_int};
74 
75 
check(f: &str, i: u32)76 fn check(f: &str, i: u32) { if i == 0 { panic!("D-Bus error: '{}' failed", f) }}
77 
ffi_iter() -> ffi::DBusMessageIter78 fn ffi_iter() -> ffi::DBusMessageIter { unsafe { mem::zeroed() }}
79 
80 #[derive(Clone, Copy)]
81 /// Helper struct for appending one or more arguments to a Message.
82 pub struct IterAppend<'a>(ffi::DBusMessageIter, &'a Message);
83 
84 impl<'a> IterAppend<'a> {
85     /// Creates a new IterAppend struct.
new(m: &'a mut Message) -> IterAppend<'a>86     pub fn new(m: &'a mut Message) -> IterAppend<'a> {
87         let mut i = ffi_iter();
88         unsafe { ffi::dbus_message_iter_init_append(message::get_message_ptr(m), &mut i) };
89         IterAppend(i, m)
90     }
91 
92     /// Appends the argument.
append<T: Append>(&mut self, a: T)93     pub fn append<T: Append>(&mut self, a: T) { a.append(self) }
94 
append_container<F: FnOnce(&mut IterAppend<'a>)>(&mut self, arg_type: ArgType, sig: Option<&CStr>, f: F)95     fn append_container<F: FnOnce(&mut IterAppend<'a>)>(&mut self, arg_type: ArgType, sig: Option<&CStr>, f: F) {
96         let mut s = IterAppend(ffi_iter(), self.1);
97         let p = sig.map(|s| s.as_ptr()).unwrap_or(ptr::null());
98         check("dbus_message_iter_open_container",
99             unsafe { ffi::dbus_message_iter_open_container(&mut self.0, arg_type as c_int, p, &mut s.0) });
100         f(&mut s);
101         check("dbus_message_iter_close_container",
102             unsafe { ffi::dbus_message_iter_close_container(&mut self.0, &mut s.0) });
103     }
104 
105     /// Low-level function to append a variant.
106     ///
107     /// Use in case the `Variant` struct is not flexible enough -
108     /// the easier way is to just call e g "append1" on a message and supply a `Variant` parameter.
109     ///
110     /// In order not to get D-Bus errors: during the call to "f" you need to call "append" on
111     /// the supplied `IterAppend` exactly once,
112     /// and with a value which has the same signature as inner_sig.
append_variant<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F)113     pub fn append_variant<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) {
114         self.append_container(ArgType::Variant, Some(inner_sig.as_cstr()), f)
115     }
116 
117     /// Low-level function to append an array.
118     ///
119     /// Use in case the `Array` struct is not flexible enough -
120     /// the easier way is to just call e g "append1" on a message and supply an `Array` parameter.
121     ///
122     /// In order not to get D-Bus errors: during the call to "f", you should only call "append" on
123     /// the supplied `IterAppend` with values which has the same signature as inner_sig.
append_array<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F)124     pub fn append_array<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) {
125         self.append_container(ArgType::Array, Some(inner_sig.as_cstr()), f)
126     }
127 
128     /// Low-level function to append a struct.
129     ///
130     /// Use in case tuples are not flexible enough -
131     /// the easier way is to just call e g "append1" on a message and supply a tuple parameter.
append_struct<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F)132     pub fn append_struct<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) {
133         self.append_container(ArgType::Struct, None, f)
134     }
135 
136     /// Low-level function to append a dict entry.
137     ///
138     /// Use in case the `Dict` struct is not flexible enough -
139     /// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter.
140     ///
141     /// In order not to get D-Bus errors: during the call to "f", you should call "append" once
142     /// for the key, then once for the value. You should only call this function for a subiterator
143     /// you got from calling "append_dict", and signatures need to match what you specified in "append_dict".
append_dict_entry<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F)144     pub fn append_dict_entry<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) {
145         self.append_container(ArgType::DictEntry, None, f)
146     }
147 
148     /// Low-level function to append a dict.
149     ///
150     /// Use in case the `Dict` struct is not flexible enough -
151     /// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter.
152     ///
153     /// In order not to get D-Bus errors: during the call to "f", you should only call "append_dict_entry"
154     /// for the subiterator - do this as many times as the number of dict entries.
append_dict<F: FnOnce(&mut IterAppend<'a>)>(&mut self, key_sig: &Signature, value_sig: &Signature, f: F)155     pub fn append_dict<F: FnOnce(&mut IterAppend<'a>)>(&mut self, key_sig: &Signature, value_sig: &Signature, f: F) {
156         let sig = format!("{{{}{}}}", key_sig, value_sig);
157         self.append_container(Array::<bool,()>::ARG_TYPE, Some(&CString::new(sig).unwrap()), f);
158     }
159 }
160 
161 
162 
163 #[derive(Clone, Copy)]
164 /// Helper struct for retrieve one or more arguments from a Message.
165 pub struct Iter<'a>(ffi::DBusMessageIter, &'a Message, u32);
166 
167 impl<'a> Iter<'a> {
168     /// Creates a new struct for iterating over the arguments of a message, starting with the first argument.
new(m: &'a Message) -> Iter<'a>169     pub fn new(m: &'a Message) -> Iter<'a> {
170         let mut i = ffi_iter();
171         unsafe { ffi::dbus_message_iter_init(message::get_message_ptr(m), &mut i) };
172         Iter(i, m, 0)
173     }
174 
175     /// Returns the current argument, if T is the argument type. Otherwise returns None.
get<T: Get<'a>>(&mut self) -> Option<T>176     pub fn get<T: Get<'a>>(&mut self) -> Option<T> {
177         T::get(self)
178     }
179 
180     /// Returns the current argument as a trait object (experimental).
181     ///
182     /// Note: For the more complex arguments (arrays / dicts / structs, and especially
183     /// combinations thereof), their internal representations are still a bit in flux.
184     /// Instead, use as_iter() to read the values of those.
185     ///
186     /// The rest are unlikely to change - Variants are `Variant<Box<RefArg>>`, strings are `String`,
187     /// paths are `Path<'static>`, signatures are `Signature<'static>`, Int32 are `i32s` and so on.
get_refarg(&mut self) -> Option<Box<RefArg + 'static>>188     pub fn get_refarg(&mut self) -> Option<Box<RefArg + 'static>> {
189         Some(match self.arg_type() {
190 	    ArgType::Array => array_impl::get_array_refarg(self),
191 	    ArgType::Variant => Box::new(Variant::new_refarg(self).unwrap()),
192 	    ArgType::Boolean => Box::new(self.get::<bool>().unwrap()),
193 	    ArgType::Invalid => return None,
194 	    ArgType::String => Box::new(self.get::<String>().unwrap()),
195 	    ArgType::DictEntry => unimplemented!(),
196 	    ArgType::Byte => Box::new(self.get::<u8>().unwrap()),
197 	    ArgType::Int16 => Box::new(self.get::<i16>().unwrap()),
198 	    ArgType::UInt16 => Box::new(self.get::<u16>().unwrap()),
199 	    ArgType::Int32 => Box::new(self.get::<i32>().unwrap()),
200 	    ArgType::UInt32 => Box::new(self.get::<u32>().unwrap()),
201 	    ArgType::Int64 => Box::new(self.get::<i64>().unwrap()),
202 	    ArgType::UInt64 => Box::new(self.get::<u64>().unwrap()),
203 	    ArgType::Double => Box::new(self.get::<f64>().unwrap()),
204 	    ArgType::UnixFd => Box::new(self.get::<OwnedFd>().unwrap()),
205 	    ArgType::Struct => Box::new(self.recurse(ArgType::Struct).unwrap().collect::<Vec<_>>()),
206 	    ArgType::ObjectPath => Box::new(self.get::<Path>().unwrap().into_static()),
207 	    ArgType::Signature => Box::new(self.get::<Signature>().unwrap().into_static()),
208         })
209     }
210 
211     /// Returns the type signature for the current argument.
signature(&mut self) -> Signature<'static>212     pub fn signature(&mut self) -> Signature<'static> {
213         unsafe {
214             let c = ffi::dbus_message_iter_get_signature(&mut self.0);
215             assert!(c != ptr::null_mut());
216             let cc = CStr::from_ptr(c);
217             let r = Signature::new(cc.to_bytes());
218             ffi::dbus_free(c as *mut c_void);
219             r.unwrap()
220         }
221     }
222 
223     /// The raw arg_type for the current item.
224     ///
225     /// Unlike Arg::arg_type, this requires access to self and is not a static method.
226     /// You can match this against Arg::arg_type for different types to understand what type the current item is.
227     /// In case you're past the last argument, this function will return 0.
arg_type(&mut self) -> ArgType228     pub fn arg_type(&mut self) -> ArgType {
229         let s = unsafe { ffi::dbus_message_iter_get_arg_type(&mut self.0) };
230         ArgType::from_i32(s as i32).unwrap()
231     }
232 
233     /// Returns false if there are no more items.
next(&mut self) -> bool234     pub fn next(&mut self) -> bool {
235         self.2 += 1;
236         unsafe { ffi::dbus_message_iter_next(&mut self.0) != 0 }
237     }
238 
239     /// Wrapper around `get` and `next`. Calls `get`, and then `next` if `get` succeeded.
240     ///
241     /// Also returns a `Result` rather than an `Option` to work better with `try!`.
242     ///
243     /// # Example
244     /// ```ignore
245     /// struct ServiceBrowserItemNew {
246     ///     interface: i32,
247     ///     protocol: i32,
248     ///     name: String,
249     ///     item_type: String,
250     ///     domain: String,
251     ///     flags: u32,
252     /// }
253     ///
254     /// fn service_browser_item_new_msg(m: &Message) -> Result<ServiceBrowserItemNew, TypeMismatchError> {
255     ///     let mut iter = m.iter_init();
256     ///     Ok(ServiceBrowserItemNew {
257     ///         interface: try!(iter.read()),
258     ///         protocol: try!(iter.read()),
259     ///         name: try!(iter.read()),
260     ///         item_type: try!(iter.read()),
261     ///         domain: try!(iter.read()),
262     ///         flags: try!(iter.read()),
263     ///     })
264     /// }
265     /// ```
read<T: Arg + Get<'a>>(&mut self) -> Result<T, TypeMismatchError>266     pub fn read<T: Arg + Get<'a>>(&mut self) -> Result<T, TypeMismatchError> {
267         let r = try!(self.get().ok_or_else(||
268              TypeMismatchError { expected: T::ARG_TYPE, found: self.arg_type(), position: self.2 }));
269         self.next();
270         Ok(r)
271     }
272 
273     /// If the current argument is a container of the specified arg_type, then a new
274     /// Iter is returned which is for iterating over the contents inside the container.
275     ///
276     /// Primarily for internal use (the "get" function is more ergonomic), but could be
277     /// useful for recursing into containers with unknown types.
recurse(&mut self, arg_type: ArgType) -> Option<Iter<'a>>278     pub fn recurse(&mut self, arg_type: ArgType) -> Option<Iter<'a>> {
279         let containers = [ArgType::Array, ArgType::DictEntry, ArgType::Struct, ArgType::Variant];
280         if !containers.iter().any(|&t| t == arg_type) { return None; }
281 
282         let mut subiter = ffi_iter();
283         unsafe {
284             if ffi::dbus_message_iter_get_arg_type(&mut self.0) != arg_type as c_int { return None };
285             ffi::dbus_message_iter_recurse(&mut self.0, &mut subiter)
286         }
287         Some(Iter(subiter, self.1, 0))
288     }
289 }
290 
291 impl<'a> fmt::Debug for Iter<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result292     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
293         let mut z = self.clone();
294         let mut t = f.debug_tuple("Iter");
295         loop {
296             t.field(&z.arg_type());
297             if !z.next() { break }
298         }
299         t.finish()
300     }
301 }
302 
303 impl<'a> Iterator for Iter<'a> {
304     type Item = Box<RefArg + 'static>;
next(&mut self) -> Option<Self::Item>305     fn next(&mut self) -> Option<Self::Item> {
306         let r = self.get_refarg();
307         if r.is_some() { self.next(); }
308         r
309     }
310 }
311 
312 /// Type of Argument
313 ///
314 /// use this to figure out, e g, which type of argument is at the current position of Iter.
315 #[repr(u8)]
316 #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)]
317 pub enum ArgType {
318     /// Dicts are Arrays of dict entries, so Dict types will have Array as ArgType.
319     Array = ffi::DBUS_TYPE_ARRAY as u8,
320     /// Variant
321     Variant = ffi::DBUS_TYPE_VARIANT as u8,
322     /// bool
323     Boolean = ffi::DBUS_TYPE_BOOLEAN as u8,
324     /// Invalid arg type - this is also the ArgType returned when there are no more arguments available.
325     Invalid = ffi::DBUS_TYPE_INVALID as u8,
326     /// String
327     String = ffi::DBUS_TYPE_STRING as u8,
328     /// Dict entry; you'll usually not encounter this one as dicts are arrays of dict entries.
329     DictEntry = ffi::DBUS_TYPE_DICT_ENTRY as u8,
330     /// u8
331     Byte = ffi::DBUS_TYPE_BYTE as u8,
332     /// i16
333     Int16 = ffi::DBUS_TYPE_INT16 as u8,
334     /// u16
335     UInt16 = ffi::DBUS_TYPE_UINT16 as u8,
336     /// i32
337     Int32 = ffi::DBUS_TYPE_INT32 as u8,
338     /// u32
339     UInt32 = ffi::DBUS_TYPE_UINT32 as u8,
340     /// i64
341     Int64 = ffi::DBUS_TYPE_INT64 as u8,
342     /// u64
343     UInt64 = ffi::DBUS_TYPE_UINT64 as u8,
344     /// f64
345     Double = ffi::DBUS_TYPE_DOUBLE as u8,
346     /// OwnedFd
347     UnixFd = ffi::DBUS_TYPE_UNIX_FD as u8,
348     /// Use tuples or Vec<Box<RefArg>> to read/write structs.
349     Struct = ffi::DBUS_TYPE_STRUCT as u8,
350     /// Path
351     ObjectPath = ffi::DBUS_TYPE_OBJECT_PATH as u8,
352     /// Signature
353     Signature = ffi::DBUS_TYPE_SIGNATURE as u8,
354 }
355 
356 const ALL_ARG_TYPES: [(ArgType, &'static str); 18] =
357     [(ArgType::Variant, "Variant"),
358     (ArgType::Array, "Array/Dict"),
359     (ArgType::Struct, "Struct"),
360     (ArgType::String, "String"),
361     (ArgType::DictEntry, "Dict entry"),
362     (ArgType::ObjectPath, "Path"),
363     (ArgType::Signature, "Signature"),
364     (ArgType::UnixFd, "OwnedFd"),
365     (ArgType::Boolean, "bool"),
366     (ArgType::Byte, "u8"),
367     (ArgType::Int16, "i16"),
368     (ArgType::Int32, "i32"),
369     (ArgType::Int64, "i64"),
370     (ArgType::UInt16, "u16"),
371     (ArgType::UInt32, "u32"),
372     (ArgType::UInt64, "u64"),
373     (ArgType::Double, "f64"),
374     (ArgType::Invalid, "nothing")];
375 
376 impl ArgType {
377     /// A str corresponding to the name of a Rust type.
as_str(self) -> &'static str378     pub fn as_str(self) -> &'static str {
379         ALL_ARG_TYPES.iter().skip_while(|a| a.0 != self).next().unwrap().1
380     }
381 
382     /// Converts an i32 to an ArgType (or an error).
from_i32(i: i32) -> Result<ArgType, String>383     pub fn from_i32(i: i32) -> Result<ArgType, String> {
384         for &(a, _) in &ALL_ARG_TYPES {
385             if a as i32 == i { return Ok(a); }
386         }
387         Err(format!("Invalid ArgType {} ({})", i, i as u8 as char))
388     }
389 }
390 
391 
392 /// Error struct to indicate a D-Bus argument type mismatch.
393 ///
394 /// Might be returned from `iter::read()`.
395 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
396 pub struct TypeMismatchError {
397     expected: ArgType,
398     found: ArgType,
399     position: u32,
400 }
401 
402 impl TypeMismatchError {
403     /// The ArgType we were trying to read, but failed
expected_arg_type(&self) -> ArgType404     pub fn expected_arg_type(&self) -> ArgType { self.expected }
405 
406     /// The ArgType we should have been trying to read, if we wanted the read to succeed
found_arg_type(&self) -> ArgType407     pub fn found_arg_type(&self) -> ArgType { self.found }
408 
409     /// At what argument was the error found?
410     ///
411     /// Returns 0 for first argument, 1 for second argument, etc.
pos(&self) -> u32412     pub fn pos(&self) -> u32 { self.position }
413 }
414 
415 impl error::Error for TypeMismatchError {
description(&self) -> &str416     fn description(&self) -> &str { "D-Bus argument type mismatch" }
cause(&self) -> Option<&error::Error>417     fn cause(&self) -> Option<&error::Error> { None }
418 }
419 
420 impl fmt::Display for TypeMismatchError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result421     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
422         write!(f, "{} at position {}: expected {}, found {}",
423             (self as &error::Error).description(),
424             self.position, self.expected.as_str(),
425             if self.expected == self.found { "same but still different somehow" } else { self.found.as_str() }
426         )
427     }
428 }
429 
430 
431 #[allow(dead_code)]
test_compile()432 fn test_compile() {
433     let mut q = IterAppend::new(unsafe { mem::transmute(0usize) });
434 
435     q.append(5u8);
436     q.append(Array::new(&[5u8, 6, 7]));
437     q.append((8u8, &[9u8, 6, 7][..]));
438     q.append(Variant((6u8, 7u8)));
439 }
440 
441