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, AppendAll, ReadAll, 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, 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(m.ptr(), &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(m.ptr(), &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 give an error if successful.
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: iter.read()?,
258 /// protocol: iter.read()?,
259 /// name: iter.read()?,
260 /// item_type: iter.read()?,
261 /// domain: iter.read()?,
262 /// flags: 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