Skip to main content

dbus/arg/
messageitem.rs

1//! MessageItem - old, enum design that is used as parameters and return values from
2//! method calls, or as data added to a signal.
3//!
4//! Note that the newer generic design (see `arg` module) is, in general, both faster
5//! and smaller than MessageItem, and should be your first hand choice
6//! whenever applicable. There is also a trait object design called `RefArg` in
7//! case the generic design is too inflexible.
8
9use crate::strings::{Signature, Path, Interface, BusName};
10
11use crate::arg;
12use crate::arg::{Iter, IterAppend, Arg, ArgType};
13use crate::arg::OwnedFd;
14use std::ffi::CStr;
15use std::{ops, any};
16
17use crate::{ffidisp::Connection, Message, Error};
18use std::collections::BTreeMap;
19use std::convert::TryFrom;
20
21#[derive(Debug,Copy,Clone)]
22/// Errors that can happen when creating a MessageItem::Array.
23pub enum ArrayError {
24    /// The array is empty.
25    EmptyArray,
26    /// The array is composed of different element types.
27    DifferentElementTypes,
28    /// The supplied signature is not a valid array signature
29    InvalidSignature,
30}
31
32
33/// OwnedFd wrapper for MessageItem
34#[cfg(feature = "stdfd")]
35#[derive(Debug)]
36pub struct MessageItemFd(pub OwnedFd);
37
38#[cfg(feature = "stdfd")]
39mod messageitem_fd_impl {
40    use super::*;
41    impl Clone for MessageItemFd {
42        fn clone(&self) -> Self { MessageItemFd(self.0.try_clone().unwrap()) }
43    }
44
45    impl PartialEq for MessageItemFd {
46        fn eq(&self, _rhs: &Self) -> bool { false }
47    }
48
49    impl PartialOrd for MessageItemFd {
50        fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
51            use std::os::unix::io::AsRawFd;
52            let a = self.0.as_raw_fd();
53            let b = other.0.as_raw_fd();
54            a.partial_cmp(&b)
55        }
56    }
57
58    impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(MessageItemFd(i)) } }
59
60    impl<'a> TryFrom<&'a MessageItem> for &'a OwnedFd {
61        type Error = ();
62        fn try_from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let MessageItem::UnixFd(ref b) = i { Ok(&b.0) } else { Err(()) } }
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, PartialOrd)]
67/// An array of MessageItem where every MessageItem is of the same type.
68pub struct MessageItemArray {
69    v: Vec<MessageItem>,
70    // signature includes the "a"!
71    sig: Signature<'static>,
72}
73
74impl MessageItemArray {
75    /// Creates a new array where every element has the supplied signature.
76    ///
77    /// Signature is the full array signature, not the signature of the element.
78    pub fn new(v: Vec<MessageItem>, sig: Signature<'static>) -> Result<MessageItemArray, ArrayError> {
79        let a = MessageItemArray {v: v, sig: sig };
80        if a.sig.as_bytes()[0] != ffi::DBUS_TYPE_ARRAY as u8 { return Err(ArrayError::InvalidSignature) }
81        {
82            let esig = a.element_signature();
83            for i in &a.v {
84                if i.signature().as_cstr() != esig { return Err(ArrayError::DifferentElementTypes) }
85            }
86        }
87        Ok(a)
88    }
89
90    fn element_signature(&self) -> &CStr {
91        let z = &self.sig.as_cstr().to_bytes_with_nul()[1..];
92        unsafe { CStr::from_bytes_with_nul_unchecked(z) }
93    }
94
95    fn make_sig(m: &MessageItem) -> Signature<'static> {
96        Signature::new(format!("a{}", m.signature())).unwrap()
97    }
98
99    /// Signature of array (full array signature)
100    pub fn signature(&self) -> &Signature<'static> { &self.sig }
101
102    /// Consumes the MessageItemArray in order to allow you to modify the individual items of the array.
103    pub fn into_vec(self) -> Vec<MessageItem> { self.v }
104}
105
106impl ops::Deref for MessageItemArray {
107    type Target = [MessageItem];
108    fn deref(&self) -> &Self::Target { &self.v }
109}
110
111impl arg::Append for MessageItemArray {
112    fn append_by_ref(&self, i: &mut IterAppend) {
113        i.append_container(ArgType::Array, Some(self.element_signature()), |s| {
114            for a in &self.v { a.append_by_ref(s) }
115        });
116    }
117}
118
119#[derive(Debug, Clone, PartialEq, PartialOrd)]
120/// An array of MessageItem where every MessageItem is of the same type.
121pub struct MessageItemDict {
122    v: Vec<(MessageItem, MessageItem)>,
123    // signature includes the "a"!
124    sig: Signature<'static>,
125}
126
127impl MessageItemDict {
128    /// Creates a new dict where every key and value elements have the supplied signature.
129    pub fn new(v: Vec<(MessageItem, MessageItem)>, keysig: Signature<'static>, valuesig: Signature<'static>) -> Result<MessageItemDict, ArrayError> {
130        let sig = Signature::from(format!("a{{{}{}}}", keysig, valuesig));
131        let a = MessageItemDict {v: v, sig: sig };
132        for (k, v) in &a.v {
133            if keysig != k.signature() || valuesig != v.signature() {
134                return Err(ArrayError::DifferentElementTypes);
135            }
136        }
137        Ok(a)
138    }
139
140    fn element_signature(&self) -> &CStr {
141        let z = &self.sig.as_cstr().to_bytes_with_nul()[1..];
142        unsafe { CStr::from_bytes_with_nul_unchecked(z) }
143    }
144
145    /// Signature of array (full array signature)
146    pub fn signature(&self) -> &Signature<'static> { &self.sig }
147
148    /// Consumes the MessageItemDict in order to allow you to modify the individual items of the dict.
149    pub fn into_vec(self) -> Vec<(MessageItem, MessageItem)> { self.v }
150}
151
152impl ops::Deref for MessageItemDict {
153    type Target = [(MessageItem, MessageItem)];
154    fn deref(&self) -> &Self::Target { &self.v }
155}
156
157impl arg::Append for MessageItemDict {
158    fn append_by_ref(&self, i: &mut IterAppend) {
159        i.append_container(ArgType::Array, Some(self.element_signature()), |s| {
160            for (k, v) in &self.v {
161                s.append_container(ArgType::DictEntry, None, |ss| {
162                    k.append_by_ref(ss);
163                    v.append_by_ref(ss);
164                });
165            }
166        });
167    }
168}
169
170/// MessageItem - used as parameters and return values from
171/// method calls, or as data added to a signal (old, enum version).
172///
173/// Note that the newer generic design (see `arg` module) is both faster
174/// and less error prone than MessageItem, and should be your first hand choice
175/// whenever applicable.
176#[derive(Debug, PartialEq, PartialOrd, Clone)]
177pub enum MessageItem {
178    /// A D-Bus array requires all elements to be of the same type.
179    /// All elements must match the Signature.
180    Array(MessageItemArray),
181    /// A D-Bus struct allows for values of different types.
182    Struct(Vec<MessageItem>),
183    /// A D-Bus variant is a wrapper around another `MessageItem`, which
184    /// can be of any type.
185    Variant(Box<MessageItem>),
186    /// A D-Bus dictionary. All keys and values are required to be of the same type.
187    /// Not all types can be dictionary keys, but all can be dictionary values.
188    Dict(MessageItemDict),
189    /// A D-Bus objectpath requires its content to be a valid objectpath,
190    /// so this cannot be any string.
191    ObjectPath(Path<'static>),
192    /// A D-Bus signature requires its content to be a valid type signature,
193    /// so this cannot be any string.
194    Signature(Signature<'static>),
195    /// A D-Bus String is zero terminated, so no \0 s in the String, please.
196    /// (D-Bus strings are also - like Rust strings - required to be valid UTF-8.)
197    Str(String),
198    /// A D-Bus boolean type.
199    Bool(bool),
200    /// A D-Bus unsigned 8 bit type.
201    Byte(u8),
202    /// A D-Bus signed 16 bit type.
203    Int16(i16),
204    /// A D-Bus signed 32 bit type.
205    Int32(i32),
206    /// A D-Bus signed 64 bit type.
207    Int64(i64),
208    /// A D-Bus unsigned 16 bit type.
209    UInt16(u16),
210    /// A D-Bus unsigned 32 bit type.
211    UInt32(u32),
212    /// A D-Bus unsigned 64 bit type.
213    UInt64(u64),
214    /// A D-Bus IEEE-754 double-precision floating point type.
215    Double(f64),
216    /// D-Bus allows for sending file descriptors, which can be used to
217    /// set up SHM, unix pipes, or other communication channels.
218    #[cfg(not(feature = "stdfd"))]
219    UnixFd(OwnedFd),
220    /// D-Bus allows for sending file descriptors, which can be used to
221    /// set up SHM, unix pipes, or other communication channels.
222    #[cfg(feature = "stdfd")]
223    UnixFd(MessageItemFd),
224}
225
226impl MessageItem {
227    /// Get the D-Bus Signature for this MessageItem.
228    pub fn signature(&self) -> Signature<'static> {
229        use crate::arg::Variant;
230        match self {
231            MessageItem::Str(_) => <String as Arg>::signature(),
232            MessageItem::Bool(_) => <bool as Arg>::signature(),
233            MessageItem::Byte(_) => <u8 as Arg>::signature(),
234            MessageItem::Int16(_) => <i16 as Arg>::signature(),
235            MessageItem::Int32(_) => <i32 as Arg>::signature(),
236            MessageItem::Int64(_) => <i64 as Arg>::signature(),
237            MessageItem::UInt16(_) => <u16 as Arg>::signature(),
238            MessageItem::UInt32(_) => <u32 as Arg>::signature(),
239            MessageItem::UInt64(_) => <u64 as Arg>::signature(),
240            MessageItem::Double(_) => <f64 as Arg>::signature(),
241            MessageItem::Array(ref a) => a.sig.clone(),
242            MessageItem::Struct(ref s) => Signature::new(format!("({})", s.iter().fold(String::new(), |s, i| s + &*i.signature()))).unwrap(),
243            MessageItem::Variant(_) => <Variant<u8> as Arg>::signature(),
244            MessageItem::Dict(ref a) => a.sig.clone(),
245            MessageItem::ObjectPath(_) => <Path as Arg>::signature(),
246            MessageItem::Signature(_) => <Signature as Arg>::signature(),
247            MessageItem::UnixFd(_) => <std::fs::File as Arg>::signature(),
248        }
249    }
250
251    /// Get the arg type of this MessageItem.
252    pub fn arg_type(&self) -> arg::ArgType {
253        match self {
254            MessageItem::Str(_) => ArgType::String,
255            MessageItem::Bool(_) => ArgType::Boolean,
256            MessageItem::Byte(_) => ArgType::Byte,
257            MessageItem::Int16(_) => ArgType::Int16,
258            MessageItem::Int32(_) => ArgType::Int32,
259            MessageItem::Int64(_) => ArgType::Int64,
260            MessageItem::UInt16(_) => ArgType::UInt16,
261            MessageItem::UInt32(_) => ArgType::UInt32,
262            MessageItem::UInt64(_) => ArgType::UInt64,
263            MessageItem::Double(_) => ArgType::Double,
264            MessageItem::Array(_) => ArgType::Array,
265            MessageItem::Struct(_) => ArgType::Struct,
266            MessageItem::Variant(_) => ArgType::Variant,
267            MessageItem::Dict(_) => ArgType::Array,
268            MessageItem::ObjectPath(_) => ArgType::ObjectPath,
269            MessageItem::Signature(_) => ArgType::Signature,
270            MessageItem::UnixFd(_) => ArgType::UnixFd,
271        }
272    }
273
274    /// Creates a (String, Variant) dictionary from an iterator with Result passthrough (an Err will abort and return that Err)
275    pub fn from_dict<E, I: Iterator<Item=Result<(String, MessageItem),E>>>(i: I) -> Result<MessageItem, E> {
276        let mut v = Vec::new();
277        for r in i {
278            let (s, vv) = r?;
279            v.push((s.into(), Box::new(vv).into()));
280        }
281        Ok(MessageItem::Dict(MessageItemDict::new(v, Signature::new("s").unwrap(), Signature::new("v").unwrap()).unwrap()))
282    }
283
284    /// Creates an MessageItem::Array from a list of MessageItems.
285    ///
286    /// Note: This requires `v` to be non-empty. See also
287    /// `MessageItem::from(&[T])`, which can handle empty arrays as well.
288    pub fn new_array(v: Vec<MessageItem>) -> Result<MessageItem, ArrayError> {
289        if v.is_empty() {
290            return Err(ArrayError::EmptyArray);
291        }
292        let s = MessageItemArray::make_sig(&v[0]);
293        Ok(MessageItem::Array(MessageItemArray::new(v, s)?))
294    }
295
296    /// Creates an MessageItem::Dict from a list of MessageItem pairs.
297    ///
298    /// Note: This requires `v` to be non-empty. See also
299    /// `MessageItem::from(&[(T1, T2)])`, which can handle empty arrays as well.
300    pub fn new_dict(v: Vec<(MessageItem, MessageItem)>) -> Result<MessageItem, ArrayError> {
301        if v.is_empty() {
302            return Err(ArrayError::EmptyArray);
303        }
304        let (s1, s2) = (v[0].0.signature(), v[0].1.signature());
305        Ok(MessageItem::Dict(MessageItemDict::new(v, s1, s2)?))
306    }
307
308    /// Get the inner value of a `MessageItem`
309    ///
310    /// # Example
311    /// ```
312    /// use dbus::arg::messageitem::MessageItem;
313    /// let m: MessageItem = 5i64.into();
314    /// let s: i64 = m.inner().unwrap();
315    /// assert_eq!(s, 5i64);
316    /// ```
317    pub fn inner<'a, T: TryFrom<&'a MessageItem>>(&'a self) -> Result<T, T::Error> {
318        T::try_from(self)
319    }
320
321    /// Get the underlying `MessageItem` of a `MessageItem::Variant`
322    ///
323    /// Nested `MessageItem::Variant`s are unwrapped recursively until a
324    /// non-`Variant` is found.
325    ///
326    /// # Example
327    /// ```
328    /// use dbus::arg::messageitem::MessageItem;
329    /// let nested = MessageItem::Variant(Box::new(6i64.into()));
330    /// let flat: MessageItem = 6i64.into();
331    /// assert_ne!(&nested, &flat);
332    /// assert_eq!(nested.peel(), &flat);
333    /// ```
334    pub fn peel(&self) -> &Self {
335        let mut current = self;
336
337        while let MessageItem::Variant(b) = current {
338            current = &*b;
339        }
340
341        current
342    }
343
344    fn new_array2<D, I>(i: I) -> MessageItem
345    where D: Into<MessageItem>, D: Default, I: Iterator<Item=D> {
346        let v: Vec<MessageItem> = i.map(|ii| ii.into()).collect();
347        let s = {
348            let d;
349            let t = if v.is_empty() { d = D::default().into(); &d } else { &v[0] };
350            MessageItemArray::make_sig(t)
351        };
352        MessageItem::Array(MessageItemArray::new(v, s).unwrap())
353    }
354
355    fn new_dict2<K, V, I>(i: I) -> MessageItem
356    where K: Into<MessageItem> + Default, V: Into<MessageItem> + Default, I: Iterator<Item=(K, V)> {
357        let v: Vec<(MessageItem, MessageItem)> = i.map(|(k, v)| (k.into(), v.into())).collect();
358        let (kt, vt) = if v.is_empty() {
359            let kd = K::default().into();
360            let vd = V::default().into();
361            (kd.signature(), vd.signature())
362        } else { (v[0].0.signature(), v[0].1.signature()) };
363        MessageItem::Dict(MessageItemDict::new(v, kt, vt).unwrap())
364    }
365}
366
367macro_rules! msgitem_convert {
368    ($t: ty, $s: ident) => {
369        impl From<$t> for MessageItem { fn from(i: $t) -> MessageItem { MessageItem::$s(i) } }
370
371        impl<'a> TryFrom<&'a MessageItem> for $t {
372            type Error = ();
373            fn try_from(i: &'a MessageItem) -> Result<$t,()> {
374                if let MessageItem::$s(b) = i.peel() { Ok(*b) } else { Err(()) }
375            }
376        }
377    }
378}
379
380msgitem_convert!(u8, Byte);
381msgitem_convert!(u64, UInt64);
382msgitem_convert!(u32, UInt32);
383msgitem_convert!(u16, UInt16);
384msgitem_convert!(i16, Int16);
385msgitem_convert!(i32, Int32);
386msgitem_convert!(i64, Int64);
387msgitem_convert!(f64, Double);
388msgitem_convert!(bool, Bool);
389
390
391
392/// Create a `MessageItem::Array`.
393impl<'a, T> From<&'a [T]> for MessageItem
394where T: Into<MessageItem> + Clone + Default {
395    fn from(i: &'a [T]) -> MessageItem {
396        MessageItem::new_array2(i.iter().cloned())
397    }
398}
399
400/// Create a `MessageItem::Dict`.
401impl<'a, T1, T2> From<&'a [(T1, T2)]> for MessageItem
402where T1: Into<MessageItem> + Clone + Default, T2: Into<MessageItem> + Clone + Default {
403    fn from(i: &'a [(T1, T2)]) -> MessageItem {
404        MessageItem::new_dict2(i.iter().cloned())
405    }
406}
407
408impl<'a> From<&'a str> for MessageItem { fn from(i: &str) -> MessageItem { MessageItem::Str(i.to_string()) } }
409
410impl From<String> for MessageItem { fn from(i: String) -> MessageItem { MessageItem::Str(i) } }
411
412impl From<Path<'static>> for MessageItem { fn from(i: Path<'static>) -> MessageItem { MessageItem::ObjectPath(i) } }
413
414impl From<Signature<'static>> for MessageItem { fn from(i: Signature<'static>) -> MessageItem { MessageItem::Signature(i) } }
415
416#[cfg(not(feature = "stdfd"))]
417impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(i) } }
418
419#[cfg(unix)]
420impl From<std::fs::File> for MessageItem {
421    fn from(i: std::fs::File) -> MessageItem {
422        use std::os::unix::io::{FromRawFd, IntoRawFd};
423        let fd = unsafe { OwnedFd::from_raw_fd(i.into_raw_fd()) };
424        fd.into()
425    }
426}
427
428/// Create a `MessageItem::Variant`
429impl From<Box<MessageItem>> for MessageItem {
430    fn from(i: Box<MessageItem>) -> MessageItem { MessageItem::Variant(i) }
431}
432
433impl<'a> TryFrom<&'a MessageItem> for &'a str {
434    type Error = ();
435    fn try_from(i: &'a MessageItem) -> Result<&'a str, Self::Error> {
436        match i.peel() {
437            MessageItem::Str(ref b) => Ok(b),
438            MessageItem::ObjectPath(ref b) => Ok(b),
439            MessageItem::Signature(ref b) => Ok(b),
440            _ => Err(()),
441        }
442    }
443}
444
445impl<'a> TryFrom<&'a MessageItem> for &'a String {
446    type Error = ();
447    fn try_from(i: &'a MessageItem) -> Result<&'a String,()> { if let MessageItem::Str(b) = i.peel() { Ok(b) } else { Err(()) } }
448}
449
450impl<'a> TryFrom<&'a MessageItem> for &'a Path<'static> {
451    type Error = ();
452    fn try_from(i: &'a MessageItem) -> Result<&'a Path<'static>,()> { if let MessageItem::ObjectPath(b) = i.peel() { Ok(b) } else { Err(()) } }
453}
454
455impl<'a> TryFrom<&'a MessageItem> for &'a Signature<'static> {
456    type Error = ();
457    fn try_from(i: &'a MessageItem) -> Result<&'a Signature<'static>,()> { if let MessageItem::Signature(b) = i.peel() { Ok(b) } else { Err(()) } }
458}
459
460impl<'a> TryFrom<&'a MessageItem> for &'a Box<MessageItem> {
461    type Error = ();
462    fn try_from(i: &'a MessageItem) -> Result<&'a Box<MessageItem>,()> { if let MessageItem::Variant(b) = i { Ok(b) } else { Err(()) } }
463}
464
465impl<'a> TryFrom<&'a MessageItem> for &'a Vec<MessageItem> {
466    type Error = ();
467    fn try_from(i: &'a MessageItem) -> Result<&'a Vec<MessageItem>,()> {
468        match i.peel() {
469            MessageItem::Array(b) => Ok(&b.v),
470            MessageItem::Struct(b) => Ok(b),
471            _ => Err(()),
472        }
473    }
474}
475
476impl<'a> TryFrom<&'a MessageItem> for &'a [MessageItem] {
477    type Error = ();
478    fn try_from(i: &'a MessageItem) -> Result<&'a [MessageItem],()> { i.inner::<&Vec<MessageItem>>().map(|s| &**s) }
479}
480
481#[cfg(not(feature = "stdfd"))]
482impl<'a> TryFrom<&'a MessageItem> for &'a OwnedFd {
483    type Error = ();
484    fn try_from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let MessageItem::UnixFd(ref b) = i { Ok(b) } else { Err(()) } }
485}
486
487impl<'a> TryFrom<&'a MessageItem> for &'a [(MessageItem, MessageItem)] {
488    type Error = ();
489    fn try_from(i: &'a MessageItem) -> Result<&'a [(MessageItem, MessageItem)],()> {
490        if let MessageItem::Dict(ref d) = i { Ok(&*d.v) } else { Err(()) }
491    }
492}
493
494
495impl arg::Append for MessageItem {
496    fn append_by_ref(&self, i: &mut IterAppend) {
497        match self {
498            MessageItem::Str(a) => a.append_by_ref(i),
499            MessageItem::Bool(a) => a.append_by_ref(i),
500            MessageItem::Byte(a) => a.append_by_ref(i),
501            MessageItem::Int16(a) => a.append_by_ref(i),
502            MessageItem::Int32(a) => a.append_by_ref(i),
503            MessageItem::Int64(a) => a.append_by_ref(i),
504            MessageItem::UInt16(a) => a.append_by_ref(i),
505            MessageItem::UInt32(a) => a.append_by_ref(i),
506            MessageItem::UInt64(a) => a.append_by_ref(i),
507            MessageItem::Double(a) => a.append_by_ref(i),
508            MessageItem::Array(a) => a.append_by_ref(i),
509            MessageItem::Struct(a) => i.append_container(ArgType::Struct, None, |s| {
510                for v in a { v.append_by_ref(s); }
511            }),
512            MessageItem::Variant(a) => {
513                i.append_container(ArgType::Variant, Some(a.signature().as_cstr()), |s| a.append_by_ref(s))
514            },
515            MessageItem::Dict(a) => a.append_by_ref(i),
516            MessageItem::ObjectPath(a) => a.append_by_ref(i),
517            MessageItem::Signature(a) => a.append_by_ref(i),
518            #[cfg(not(feature = "stdfd"))]
519            MessageItem::UnixFd(a) => a.append_by_ref(i),
520            #[cfg(feature = "stdfd")]
521            MessageItem::UnixFd(a) => a.0.append_by_ref(i),
522        }
523    }
524}
525
526impl<'a> arg::Get<'a> for MessageItem {
527    fn get(i: &mut Iter<'a>) -> Option<Self> {
528        Some(match i.arg_type() {
529            ArgType::Array => {
530                let mut s = i.recurse(ArgType::Array).unwrap();
531                if i.signature().as_bytes()[1] == b'{' { // Dict
532                    let mut v = vec!();
533                    while s.arg_type() == ArgType::DictEntry {
534                        let mut ss = s.recurse(ArgType::DictEntry).unwrap();
535                        let kk = MessageItem::get(&mut ss).unwrap();
536                        ss.next();
537                        let vv = MessageItem::get(&mut ss).unwrap();
538                        v.push((kk, vv));
539                        s.next();
540                    };
541                    MessageItem::Dict(MessageItemDict { v: v, sig:  i.signature() })
542                } else {
543                    let mut v = vec!();
544                    while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); };
545                    MessageItem::Array(MessageItemArray { v: v, sig: i.signature() })
546                }
547            },
548            ArgType::Variant => MessageItem::Variant({
549                let mut s = i.recurse(ArgType::Variant).unwrap();
550                Box::new(MessageItem::get(&mut s).unwrap())
551            }),
552            ArgType::Boolean => MessageItem::Bool(i.get::<bool>().unwrap()),
553            ArgType::Invalid => return None,
554            ArgType::String => MessageItem::Str(i.get::<String>().unwrap()),
555            ArgType::DictEntry => return None,
556            ArgType::Byte => MessageItem::Byte(i.get::<u8>().unwrap()),
557            ArgType::Int16 => MessageItem::Int16(i.get::<i16>().unwrap()),
558            ArgType::UInt16 => MessageItem::UInt16(i.get::<u16>().unwrap()),
559            ArgType::Int32 => MessageItem::Int32(i.get::<i32>().unwrap()),
560            ArgType::UInt32 => MessageItem::UInt32(i.get::<u32>().unwrap()),
561            ArgType::Int64 => MessageItem::Int64(i.get::<i64>().unwrap()),
562            ArgType::UInt64 => MessageItem::UInt64(i.get::<u64>().unwrap()),
563            ArgType::Double => MessageItem::Double(i.get::<f64>().unwrap()),
564            #[cfg(not(feature = "stdfd"))]
565            ArgType::UnixFd => MessageItem::UnixFd(i.get::<OwnedFd>().unwrap()),
566            #[cfg(feature = "stdfd")]
567            ArgType::UnixFd => MessageItem::UnixFd(MessageItemFd(i.get::<OwnedFd>().unwrap())),
568            ArgType::Struct => MessageItem::Struct({
569                let mut s = i.recurse(ArgType::Struct).unwrap();
570                let mut v = vec!();
571                while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); };
572                v
573            }),
574            ArgType::ObjectPath => MessageItem::ObjectPath(i.get::<Path>().unwrap().into_static()),
575            ArgType::Signature => MessageItem::Signature(i.get::<Signature>().unwrap().into_static()),
576        })
577    }
578}
579
580impl arg::RefArg for MessageItem {
581    fn arg_type(&self) -> ArgType { MessageItem::arg_type(&self) }
582    fn signature(&self) -> Signature<'static> { MessageItem::signature(&self) }
583    fn append(&self, i: &mut IterAppend) { arg::Append::append_by_ref(self, i) }
584    #[inline]
585    fn as_any(&self) -> &dyn any::Any where Self: 'static { self }
586    #[inline]
587    fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self }
588    #[inline]
589    fn box_clone(&self) -> Box<dyn arg::RefArg + 'static> { Box::new(self.clone()) }
590}
591
592
593impl arg::Append for arg::Variant<MessageItem> {
594    fn append_by_ref(&self, i: &mut IterAppend) {
595        let z = &self.0;
596        let asig = z.signature();
597        let sig = asig.as_cstr();
598        i.append_container(ArgType::Variant, Some(&sig), |s| z.append_by_ref(s));
599    }
600}
601
602
603/// Client side properties - get and set properties on a remote application.
604pub struct Props<'a> {
605    name: BusName<'a>,
606    path: Path<'a>,
607    interface: Interface<'a>,
608    timeout_ms: i32,
609    conn: &'a Connection,
610}
611
612impl<'a> Props<'a> {
613    /// Create a new Props.
614    pub fn new<N, P, I>(conn: &'a Connection, name: N, path: P, interface: I, timeout_ms: i32) -> Props<'a>
615    where N: Into<BusName<'a>>, P: Into<Path<'a>>, I: Into<Interface<'a>> {
616        Props {
617            name: name.into(),
618            path: path.into(),
619            interface: interface.into(),
620            timeout_ms: timeout_ms,
621            conn: conn,
622        }
623    }
624
625    /// Get a single property's value.
626    pub fn get(&self, propname: &str) -> Result<MessageItem, Error> {
627        let mut m = Message::method_call(&self.name, &self.path,
628            &"org.freedesktop.DBus.Properties".into(), &"Get".into());
629        m.append_items(&[self.interface.to_string().into(), propname.to_string().into()]);
630        let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
631        let reply = r.as_result()?.get_items();
632        if reply.len() == 1 {
633            if let MessageItem::Variant(ref v) = reply[0] {
634                return Ok((**v).clone())
635            }
636       }
637       let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply);
638       Err(Error::new_custom("InvalidReply", &f))
639    }
640
641    /// Set a single property's value.
642    pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> {
643        let mut m = Message::method_call(&self.name, &self.path,
644            &"org.freedesktop.DBus.Properties".into(), &"Set".into());
645        m.append_items(&[self.interface.to_string().into(), propname.to_string().into(), Box::new(value).into()]);
646        let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
647        r.as_result()?;
648        Ok(())
649    }
650
651    /// Get a map of all the properties' names and their values.
652    pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> {
653        let mut m = Message::method_call(&self.name, &self.path,
654            &"org.freedesktop.DBus.Properties".into(), &"GetAll".into());
655        m.append_items(&[self.interface.to_string().into()]);
656        let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
657        let reply = r.as_result()?.get_items();
658
659        (|| {
660            if reply.len() != 1 { return Err(()) };
661            let mut tree = BTreeMap::new();
662            let a: &[(MessageItem, MessageItem)] = reply[0].inner()?;
663            for (k, v) in a.iter() {
664                let (k, v): (&String, &Box<MessageItem>) = (k.inner()?, v.inner()?);
665                tree.insert(k.clone(), *v.clone());
666            }
667            Ok(tree)
668        })().map_err(|_| {
669            let f = format!("Invalid reply for property GetAll: '{:?}'", reply);
670            Error::new_custom("InvalidReply", &f)
671        })
672    }
673}
674
675/// Wrapper around Props that keeps a map of fetched properties.
676pub struct PropHandler<'a> {
677    p: Props<'a>,
678    map: BTreeMap<String, MessageItem>,
679}
680
681impl<'a> PropHandler<'a> {
682    /// Create a new PropHandler from a Props.
683    pub fn new(p: Props) -> PropHandler {
684        PropHandler { p: p, map: BTreeMap::new() }
685    }
686
687    /// Get a map of all the properties' names and their values.
688    pub fn get_all(&mut self) -> Result<(), Error> {
689        self.map = self.p.get_all()?;
690        Ok(())
691    }
692
693    /// Get a mutable reference to the PropHandler's fetched properties.
694    pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map }
695
696    /// Get a reference to the PropHandler's fetched properties.
697    pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map }
698
699    /// Get a single property's value.
700    pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> {
701        let v = self.p.get(propname)?;
702        self.map.insert(propname.to_string(), v);
703        Ok(self.map.get(propname).unwrap())
704    }
705
706    /// Set a single property's value.
707    pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> {
708        self.p.set(propname, value.clone())?;
709        self.map.insert(propname.to_string(), value);
710        Ok(())
711    }
712}
713
714
715#[cfg(test)]
716mod test {
717    extern crate tempfile;
718
719    use crate::{Message, MessageType, Path, Signature};
720    use crate::arg::messageitem::MessageItem;
721    use crate::ffidisp::{Connection, BusType};
722
723    #[test]
724    fn unix_fd() {
725        use std::io::prelude::*;
726        use std::io::SeekFrom;
727        use std::fs::OpenOptions;
728
729        let c = Connection::get_private(BusType::Session).unwrap();
730        c.register_object_path("/hello").unwrap();
731        let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
732        let tempdir = tempfile::Builder::new().prefix("dbus-rs-test").tempdir().unwrap();
733        let mut filename = tempdir.path().to_path_buf();
734        filename.push("test");
735        println!("Creating file {:?}", filename);
736        let mut file = OpenOptions::new().create(true).read(true).write(true).open(&filename).unwrap();
737        file.write_all(b"z").unwrap();
738        file.seek(SeekFrom::Start(0)).unwrap();
739        #[cfg(unix)]
740        {
741            m.append_items(&[file.into()]);
742        }
743        println!("Sending {:?}", m.get_items());
744        c.send(m).unwrap();
745
746        loop { for n in c.incoming(1000) {
747            if n.msg_type() == MessageType::MethodCall {
748                #[cfg(unix)]
749                {
750                    use std::os::unix::io::AsRawFd;
751                    let z: crate::arg::OwnedFd = n.read1().unwrap();
752                    println!("Got {:?}", z);
753                    let mut q: libc::c_char = 100;
754                    assert_eq!(1, unsafe { libc::read(z.as_raw_fd(), &mut q as *mut _ as *mut libc::c_void, 1) });
755                    assert_eq!(q, 'z' as libc::c_char);
756                }
757                return;
758            } else {
759                println!("Got {:?}", n);
760            }
761        }}
762    }
763
764    #[test]
765    fn message_types() {
766        let c = Connection::get_private(BusType::Session).unwrap();
767        c.register_object_path("/hello").unwrap();
768        let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
769        m.append_items(&[
770            2000u16.into(),
771            MessageItem::new_array(vec!(129u8.into())).unwrap(),
772            ["Hello", "world"][..].into(),
773            987654321u64.into(),
774            (-1i32).into(),
775            format!("Hello world").into(),
776            (-3.14f64).into(),
777            MessageItem::Struct(vec!(256i16.into())),
778            Path::new("/some/path").unwrap().into(),
779            MessageItem::new_dict(vec!((123543u32.into(), true.into()).into())).unwrap()
780        ]);
781        let sending = format!("{:?}", m.get_items());
782        println!("Sending {}", sending);
783        c.send(m).unwrap();
784
785        loop { for n in c.incoming(1000) {
786            if n.msg_type() == MessageType::MethodCall {
787                let receiving = format!("{:?}", n.get_items());
788                println!("Receiving {}", receiving);
789                assert_eq!(sending, receiving);
790                return;
791            } else {
792                println!("Got {:?}", n);
793            }
794        }}
795    }
796
797    #[test]
798    fn dict_of_dicts() {
799        use std::collections::BTreeMap;
800
801        let officeactions: BTreeMap<&'static str, MessageItem> = BTreeMap::new();
802        let mut officethings = BTreeMap::new();
803        officethings.insert("pencil", 2u16.into());
804        officethings.insert("paper", 5u16.into());
805        let mut homethings = BTreeMap::new();
806        homethings.insert("apple", 11u16.into());
807        let mut homeifaces = BTreeMap::new();
808        homeifaces.insert("getThings", homethings);
809        let mut officeifaces = BTreeMap::new();
810        officeifaces.insert("getThings", officethings);
811        officeifaces.insert("getActions", officeactions);
812        let mut paths = BTreeMap::new();
813        paths.insert("/hello/office", officeifaces);
814        paths.insert("/hello/home", homeifaces);
815
816        println!("Original treemap: {:?}", paths);
817        let m = MessageItem::new_dict(paths.iter().map(
818            |(path, ifaces)| (MessageItem::ObjectPath(Path::new(*path).unwrap()),
819                MessageItem::new_dict(ifaces.iter().map(
820                    |(iface, props)| (iface.to_string().into(),
821                        MessageItem::from_dict::<(),_>(props.iter().map(
822                            |(name, value)| Ok((name.to_string(), value.clone()))
823                        )).unwrap()
824                    ).into()
825                ).collect()).unwrap()
826            ).into()
827        ).collect()).unwrap();
828        println!("As MessageItem: {:?}", m);
829        assert_eq!(&*m.signature(), "a{oa{sa{sv}}}");
830
831        let c = Connection::get_private(BusType::Session).unwrap();
832        c.register_object_path("/hello").unwrap();
833        let mut msg = Message::new_method_call(&c.unique_name(), "/hello", "org.freedesktop.DBusObjectManager", "GetManagedObjects").unwrap();
834        msg.append_items(&[m]);
835        let sending = format!("{:?}", msg.get_items());
836        println!("Sending {}", sending);
837        c.send(msg).unwrap();
838
839        loop { for n in c.incoming(1000) {
840            if n.msg_type() == MessageType::MethodCall {
841                let receiving = format!("{:?}", n.get_items());
842                println!("Receiving {}", receiving);
843                assert_eq!(sending, receiving);
844                return;
845            } else {
846                println!("Got {:?}", n);
847            }
848        } }
849    }
850
851    #[test]
852    fn issue24() {
853        let c = Connection::get_private(BusType::Session).unwrap();
854        let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap();
855
856        let a = MessageItem::from("test".to_string());
857        let b = MessageItem::from("test".to_string());
858        let foo = MessageItem::Struct(vec!(a, b));
859        let bar = foo.clone();
860
861        let args = [MessageItem::new_array(vec!(foo, bar)).unwrap()];
862        println!("{:?}", args);
863
864        m.append_items(&args);
865        c.send(m).unwrap();
866    }
867
868    /* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but hostname1 should be around on most distros. */
869    #[cfg(unix)]
870    #[test]
871    fn test_get_hostname1_prop() {
872        use super::Props;
873
874        let c = Connection::new_system().unwrap();
875        let p = Props::new(&c, "org.freedesktop.hostname1", "/org/freedesktop/hostname1",
876            "org.freedesktop.hostname1", 10000);
877
878        /* Let's use both the get and getall methods and see if we get the same result */
879        let v = p.get("StaticHostname").unwrap();
880        let vall = p.get_all().unwrap();
881        let v2 = vall.get("StaticHostname").unwrap();
882
883        assert_eq!(&v, &*v2);
884        match v {
885            MessageItem::Str(ref s) => { println!("StaticHostname is {}", s); }
886            _ => { panic!("Invalid Get: {:?}", v); }
887        };
888    }
889
890    #[test]
891    fn message_listnames() {
892        let c = Connection::get_private(BusType::Session).unwrap();
893        let m = Message::method_call(&"org.freedesktop.DBus".into(), &"/".into(),
894            &"org.freedesktop.DBus".into(), &"ListNames".into());
895        let r = c.send_with_reply_and_block(m, 2000).unwrap();
896        let reply = r.get_items();
897        println!("{:?}", reply);
898    }
899
900    #[test]
901    fn message_namehasowner() {
902        let c = Connection::get_private(BusType::Session).unwrap();
903        let mut m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "NameHasOwner").unwrap();
904        m.append_items(&[MessageItem::Str("org.freedesktop.DBus".to_string())]);
905        let r = c.send_with_reply_and_block(m, 2000).unwrap();
906        let reply = r.get_items();
907        println!("{:?}", reply);
908        assert_eq!(reply, vec!(MessageItem::Bool(true)));
909    }
910
911    #[test]
912    fn message_inner_str() {
913        let ob = MessageItem::ObjectPath("/path".into());
914        assert_eq!("/path", ob.inner::<&str>().unwrap());
915
916        let ob = MessageItem::ObjectPath("/path".into());
917        assert_ne!("/path/another", ob.inner::<&str>().unwrap());
918
919        let ob = MessageItem::Str("String".into());
920        assert_eq!("String", ob.inner::<&str>().unwrap());
921
922        let ob = MessageItem::Str("String".into());
923        assert_ne!("StringDiff", ob.inner::<&str>().unwrap());
924
925        let ob = MessageItem::Signature(Signature::make::<i32>());
926        assert_eq!("i", ob.inner::<&str>().unwrap());
927
928        let ob = MessageItem::Signature(Signature::make::<u32>());
929        assert_ne!("i", ob.inner::<&str>().unwrap());
930
931    }
932
933    #[test]
934    fn message_peel() {
935        let flat_str = MessageItem::Str("foobar".into());
936        assert_eq!(flat_str.peel(), &flat_str);
937
938        let flat_path = MessageItem::ObjectPath("/path".into());
939        assert_eq!(flat_path.peel(), &flat_path);
940
941        let flat_sig = MessageItem::Signature(Signature::make::<i32>());
942        assert_eq!(flat_sig.peel(), &flat_sig);
943
944        let flat_int = MessageItem::Int32(1234);
945        assert_eq!(flat_int.peel(), &flat_int);
946
947        let layered_str = MessageItem::Variant(Box::new(flat_str));
948        assert_eq!(layered_str.peel(), &MessageItem::Str("foobar".into()));
949
950        let layered_path = MessageItem::Variant(Box::new(flat_path));
951        assert_eq!(layered_path.peel(), &MessageItem::ObjectPath("/path".into()));
952
953        let layered_sig = MessageItem::Variant(Box::new(flat_sig));
954        assert_eq!(layered_sig.peel(), &MessageItem::Signature(Signature::make::<i32>()));
955
956        let layered_int = MessageItem::Variant(Box::new(flat_int));
957        assert_eq!(layered_int.peel(), &MessageItem::Int32(1234));
958
959        let very_deep =
960            MessageItem::Variant(Box::new(
961            MessageItem::Variant(Box::new(
962            MessageItem::Variant(Box::new(
963            MessageItem::Variant(Box::new(
964            MessageItem::Variant(Box::new(
965            MessageItem::Variant(Box::new(
966            MessageItem::Variant(Box::new(
967            MessageItem::Variant(Box::new(
968            MessageItem::Variant(Box::new(
969            MessageItem::Variant(Box::new(
970            MessageItem::Int32(1234)
971            ))))))))))))))))))));
972
973        assert_eq!(very_deep.peel(), &MessageItem::Int32(1234));
974
975    }
976
977    #[test]
978    fn inner_from_variant() {
979        let msg_u8 = MessageItem::Variant(Box::new(3u8.into()));
980        assert_eq!(msg_u8.inner::<u8>().unwrap(), 3u8);
981
982        let msg_u16 = MessageItem::Variant(Box::new(4u16.into()));
983        assert_eq!(msg_u16.inner::<u16>().unwrap(), 4u16);
984
985        let msg_u32 = MessageItem::Variant(Box::new(5u32.into()));
986        assert_eq!(msg_u32.inner::<u32>().unwrap(), 5u32);
987
988        let msg_u64 = MessageItem::Variant(Box::new(6u64.into()));
989        assert_eq!(msg_u64.inner::<u64>().unwrap(), 6u64);
990
991        let msg_i16 = MessageItem::Variant(Box::new(4i16.into()));
992        assert_eq!(msg_i16.inner::<i16>().unwrap(), 4i16);
993
994        let msg_i32 = MessageItem::Variant(Box::new(5i32.into()));
995        assert_eq!(msg_i32.inner::<i32>().unwrap(), 5i32);
996
997        let msg_i64 = MessageItem::Variant(Box::new(6i64.into()));
998        assert_eq!(msg_i64.inner::<i64>().unwrap(), 6i64);
999
1000        let msg_f64 = MessageItem::Variant(Box::new(6.5f64.into()));
1001        assert_eq!(msg_f64.inner::<f64>().unwrap(), 6.5f64);
1002
1003        let msg_bool = MessageItem::Variant(Box::new(false.into()));
1004        assert_eq!(msg_bool.inner::<bool>().unwrap(), false);
1005
1006        let msg_string = MessageItem::Variant(Box::new("asdf".to_string().into()));
1007        assert_eq!(msg_string.inner::<&String>().unwrap(), "asdf");
1008
1009        let path: Path = "/path".into();
1010        let msg_path = MessageItem::Variant(Box::new(MessageItem::ObjectPath(path.clone())));
1011        assert_eq!(msg_path.inner::<&Path>().unwrap(), &path);
1012
1013        let sig: Signature = "a{si}".into();
1014        let msg_sig = MessageItem::Variant(Box::new(MessageItem::Signature(sig.clone())));
1015        assert_eq!(msg_sig.inner::<&Signature>().unwrap(), &sig);
1016
1017        assert_eq!(msg_string.inner::<&str>().unwrap(), "asdf");
1018        assert_eq!(msg_path.inner::<&str>().unwrap(), "/path");
1019        assert_eq!(msg_sig.inner::<&str>().unwrap(), "a{si}");
1020
1021    }
1022
1023}