dbus/arg/
msgarg.rs

1#![allow(dead_code)]
2
3use crate::{Signature, arg::TypeMismatchError, arg::Variant};
4use std::{fmt, any};
5use std::sync::Arc;
6// use std::rc::Rc;
7use std::collections::{HashMap, VecDeque};
8
9use super::{Iter, IterAppend, ArgType};
10
11/// Types that can represent a D-Bus message argument implement this trait.
12///
13/// Types should also implement either Append or Get to be useful.
14pub trait Arg {
15    /// The corresponding D-Bus argument type code.
16    const ARG_TYPE: ArgType;
17    /// The corresponding D-Bus type signature for this type.
18    fn signature() -> Signature<'static>;
19}
20
21/// Helper trait to introspect many arguments.
22pub trait ArgAll {
23    /// A tuple of &static str. Used for introspection.
24    #[allow(non_camel_case_types)] // Note: This should be changed for 0.9 - but for now, don't break backwards compatibility
25    type strs;
26    /// Enumerates all arguments with their signatures (introspection helper method).
27    fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(a: Self::strs, f: F);
28}
29
30/// Types that can be appended to a message as arguments implement this trait.
31pub trait Append {
32    /// Performs the append operation by consuming self.
33    fn append(self, ia: &mut IterAppend) where Self: Sized { self.append_by_ref(ia) }
34
35    /// Performs the append operation by borrowing self.
36    fn append_by_ref(&self, _: &mut IterAppend);
37}
38
39/// Helper trait to append many arguments to a message.
40pub trait AppendAll {
41    /// Performs the append operation by borrowing self.
42    fn append(&self, _: &mut IterAppend);
43}
44
45/// Types that can be retrieved from a message as arguments implement this trait.
46pub trait Get<'a>: Sized {
47    /// Performs the get operation.
48    fn get(i: &mut Iter<'a>) -> Option<Self>;
49}
50
51/// Helper trait to read all arguments from a message.
52pub trait ReadAll: Sized {
53    /// Performs the read operation.
54    fn read(i: &mut Iter) -> Result<Self, TypeMismatchError>;
55}
56
57
58/// Object safe version of Arg + Append + Get.
59pub trait RefArg: fmt::Debug + Send + Sync {
60    /// The corresponding D-Bus argument type code.
61    fn arg_type(&self) -> ArgType;
62    /// The corresponding D-Bus type signature for this type.
63    fn signature(&self) -> Signature<'static>;
64    /// Performs the append operation.
65    fn append(&self, _: &mut IterAppend);
66    /// Transforms this argument to Any (which can be downcasted to read the current value).
67    ///
68    /// See the argument guide's reference section for which types you can cast to.
69    fn as_any(&self) -> &dyn any::Any where Self: 'static;
70    /// Transforms this argument to Any (which can be downcasted to read the current value).
71	///
72    /// See the argument guide's reference section for which types you can cast to.
73    /// # Panic
74    /// Will panic if the interior cannot be made mutable, e g, if encapsulated
75    /// inside a Rc with a reference count > 1.
76    fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static;
77    /// Try to read the argument as an i64.
78    ///
79    /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Int64, UnixFd.
80    #[inline]
81    fn as_i64(&self) -> Option<i64> { None }
82    /// Try to read the argument as an u64.
83    ///
84    /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, UInt64.
85    #[inline]
86    fn as_u64(&self) -> Option<u64> { None }
87    /// Try to read the argument as an f64.
88    ///
89    /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Double.
90    #[inline]
91    fn as_f64(&self) -> Option<f64> { None }
92    /// Try to read the argument as a str.
93    ///
94    /// Works for: String, ObjectPath, Signature.
95    #[inline]
96    fn as_str(&self) -> Option<&str> { None }
97    /// Try to read the argument as an iterator.
98    ///
99    /// Works for: Array/Dict, Struct, Variant.
100    /// For Dicts, keys and values are interleaved.
101    #[inline]
102    fn as_iter<'a>(&'a self) -> Option<Box<dyn Iterator<Item=&'a dyn RefArg> + 'a>> { None }
103    /// Try to read the inner of an argument, as another argument, specifying an index.
104    ///
105    /// Works for: Variant, Array, Struct, Dict.
106    /// For Dicts, even indices gets a key, odd indices gets a value.
107    #[inline]
108    fn as_static_inner(&self, _index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { None }
109    /// Deep clone of the RefArg, causing the result to be 'static.
110    ///
111    /// Usable as an escape hatch in case of lifetime problems with RefArg.
112    ///
113    /// In case of complex types (Array, Dict, Struct), the clone is not guaranteed
114    /// to have the same internal representation as the original.
115    fn box_clone(&self) -> Box<dyn RefArg + 'static>;
116
117    /// Deep clone of an array.
118    ///
119    /// This method is used internally by box_clone.
120    fn array_clone(_arg: &[Self]) -> Option<Box<dyn RefArg + 'static>> where Self: Sized { None }
121}
122
123impl<'a> Get<'a> for Box<dyn RefArg> {
124    fn get(i: &mut Iter<'a>) -> Option<Self> { i.get_refarg() }
125}
126
127/// Cast a RefArg as a specific type (shortcut for any + downcast)
128///
129/// See the argument guide's reference section for which types you can cast to.
130#[inline]
131pub fn cast<'a, T: 'static>(a: &'a (dyn RefArg + 'static)) -> Option<&'a T> { a.as_any().downcast_ref() }
132
133/// Cast a RefArg as a specific type (shortcut for any_mut + downcast_mut)
134///
135/// See the argument guide's reference section for which types you can cast to.
136///
137/// # Panic
138/// Will panic if the interior cannot be made mutable, e g, if encapsulated
139/// inside a Rc with a reference count > 1.
140#[inline]
141pub fn cast_mut<'a, T: 'static>(a: &'a mut (dyn RefArg + 'static)) -> Option<&'a mut T> { a.as_any_mut().downcast_mut() }
142
143/// The type typically used for a dictionary of properties.
144pub type PropMap = HashMap<String, Variant<Box<dyn RefArg + 'static>>>;
145
146
147/// Descend into a hashmap returned by e g "Properties::get_all" to retrieve the value of a property.
148///
149/// Shortcut for get + cast. Returns None both if the property does not exist, or if it was of a different type.
150/// See the argument guide's reference section for which types you can cast to.
151pub fn prop_cast<'a, T: 'static>(map: &'a PropMap, key: &str) -> Option<&'a T> {
152    map.get(key).and_then(|v| cast(&v.0))
153}
154
155/// If a type implements this trait, it means the size and alignment is the same
156/// as in D-Bus. This means that you can quickly append and get slices of this type.
157///
158/// Note: Booleans do not implement this trait because D-Bus booleans are 4 bytes and Rust booleans are 1 byte.
159pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {}
160
161/// Types that can be used as keys in a dict type implement this trait.
162pub trait DictKey: Arg {}
163
164
165
166/// Simple lift over reference to value - this makes some iterators more ergonomic to use
167impl<'a, T: Arg> Arg for &'a T {
168    const ARG_TYPE: ArgType = T::ARG_TYPE;
169    fn signature() -> Signature<'static> { T::signature() }
170}
171impl<'a, T: Append> Append for &'a T {
172    fn append_by_ref(&self, i: &mut IterAppend) { (&**self).append_by_ref(i) }
173}
174impl<'a, T: DictKey> DictKey for &'a T {}
175
176impl<'a, T: RefArg + ?Sized> RefArg for &'a T {
177    #[inline]
178    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
179    #[inline]
180    fn signature(&self) -> Signature<'static> { (&**self).signature() }
181    #[inline]
182    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
183    #[inline]
184    fn as_any(&self) -> &dyn any::Any where T: 'static { (&**self).as_any() }
185    #[inline]
186    fn as_any_mut(&mut self) -> &mut dyn any::Any where T: 'static { unreachable!() }
187    #[inline]
188    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
189    #[inline]
190    fn as_u64(&self) -> Option<u64> { (&**self).as_u64() }
191    #[inline]
192    fn as_f64(&self) -> Option<f64> { (&**self).as_f64() }
193    #[inline]
194    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
195    #[inline]
196    fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item=&'b dyn RefArg> + 'b>> { (&**self).as_iter() }
197    #[inline]
198    fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { (&**self).as_static_inner(index) }
199    #[inline]
200    fn box_clone(&self) -> Box<dyn RefArg + 'static> { (&**self).box_clone() }
201}
202
203
204
205macro_rules! deref_impl {
206    ($t: ident, $ss: ident, $make_mut: expr) => {
207
208impl<T: RefArg + ?Sized> RefArg for $t<T> {
209    #[inline]
210    fn arg_type(&self) -> ArgType { (&**self).arg_type() }
211    #[inline]
212    fn signature(&self) -> Signature<'static> { (&**self).signature() }
213    #[inline]
214    fn append(&self, i: &mut IterAppend) { (&**self).append(i) }
215    #[inline]
216    fn as_any(&self) -> &dyn any::Any where T: 'static { (&**self).as_any() }
217    #[inline]
218    fn as_any_mut(&mut $ss) -> &mut dyn any::Any where T: 'static { $make_mut.as_any_mut() }
219    #[inline]
220    fn as_i64(&self) -> Option<i64> { (&**self).as_i64() }
221    #[inline]
222    fn as_u64(&self) -> Option<u64> { (&**self).as_u64() }
223    #[inline]
224    fn as_f64(&self) -> Option<f64> { (&**self).as_f64() }
225    #[inline]
226    fn as_str(&self) -> Option<&str> { (&**self).as_str() }
227    #[inline]
228    fn as_iter<'a>(&'a self) -> Option<Box<dyn Iterator<Item=&'a dyn RefArg> + 'a>> { (&**self).as_iter() }
229    #[inline]
230    fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { (&**self).as_static_inner(index) }
231    #[inline]
232    fn box_clone(&self) -> Box<dyn RefArg + 'static> { (&**self).box_clone() }
233}
234impl<T: DictKey> DictKey for $t<T> {}
235
236impl<T: Arg> Arg for $t<T> {
237    const ARG_TYPE: ArgType = T::ARG_TYPE;
238    fn signature() -> Signature<'static> { T::signature() }
239}
240impl<'a, T: Get<'a>> Get<'a> for $t<T> {
241    fn get(i: &mut Iter<'a>) -> Option<Self> { T::get(i).map($t::new) }
242}
243
244    }
245}
246
247impl<T: Append> Append for Box<T> {
248    fn append_by_ref(&self, i: &mut IterAppend) { (&**self).append_by_ref(i) }
249}
250
251deref_impl!(Box, self, &mut **self );
252// deref_impl!(Rc, self, Rc::get_mut(self).unwrap());
253deref_impl!(Arc, self, Arc::get_mut(self).unwrap());
254
255macro_rules! argall_impl {
256    ($($n: ident $t: ident $s: ty,)+) => {
257
258impl<$($t: Arg),*> ArgAll for ($($t,)*) {
259    type strs = ($(&'static $s,)*);
260    fn strs_sig<Q: FnMut(&'static str, Signature<'static>)>(z: Self::strs, mut q: Q) {
261        let ( $($n,)*) = z;
262        $( q($n, $t::signature()); )*
263    }
264}
265
266impl<$($t: Append),*> AppendAll for ($($t,)*) {
267    fn append(&self, ia: &mut IterAppend) {
268        let ( $($n,)*) = self;
269        $( ia.append($n); )*
270    }
271}
272
273impl<$($t: Arg + for<'z> Get<'z>),*> ReadAll for ($($t,)*) {
274    fn read(ii: &mut Iter) -> Result<Self, TypeMismatchError> {
275        $( let $n = ii.read()?; )*
276        Ok(($( $n, )* ))
277    }
278}
279
280
281    }
282}
283
284impl ArgAll for () {
285    type strs = ();
286    fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(_: Self::strs, _: F) {}
287}
288
289impl AppendAll for () {
290    fn append(&self, _: &mut IterAppend) {}
291}
292
293impl ReadAll for () {
294    fn read(_: &mut Iter) -> Result<Self, TypeMismatchError> {
295        Ok(())
296    }
297}
298
299
300/// This is a fallback for methods that have tons of arguments.
301/// Usually we'll use a tuple because it is more ergonomic, but AppendAll is only
302/// implemented for tuples up to a certain size.
303impl AppendAll for VecDeque<Box<dyn RefArg>> {
304    fn append(&self, ia: &mut IterAppend) {
305        for arg in self {
306            arg.append(ia);
307        }
308    }
309}
310
311/// This is a fallback for methods that have tons of arguments.
312/// Usually we'll use a tuple because it is more ergonomic, but ReadAll is only
313/// implemented for tuples up to a certain size.
314impl ReadAll for VecDeque<Box<dyn RefArg>> {
315    fn read(ii: &mut Iter) -> Result<Self, TypeMismatchError> {
316        let mut r = VecDeque::new();
317        while let Some(arg) = ii.get_refarg() {
318            r.push_back(arg);
319            ii.next();
320        }
321        Ok(r)
322    }
323}
324
325
326argall_impl!(a A str,);
327argall_impl!(a A str, b B str,);
328argall_impl!(a A str, b B str, c C str,);
329argall_impl!(a A str, b B str, c C str, d D str,);
330argall_impl!(a A str, b B str, c C str, d D str, e E str,);
331argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str,);
332argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str,);
333argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str,);
334argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str,);
335argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str,);
336argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str,);
337argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str,);
338argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str,);
339argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str,);
340argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str,);
341argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str,);
342argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str,);
343argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str,);
344argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str,);
345argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str,);
346argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str, v V str,);
347argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str, v V str, w W str,);
348argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str, v V str, w W str, x X str,);
349argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str, v V str, w W str, x X str, y Y str,);
350argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str, h H str, i I str, j J str, k K str, l L str, m M str, n N str, o O str, p P str, r R str, s S str, t T str, u U str, v V str, w W str, x X str, y Y str, z Z str,);
351
352
353#[cfg(test)]
354mod test {
355    use crate::{channel::{Channel, BusType}, Message, Path, Signature};
356    use crate::message::MessageType;
357    use crate::arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast};
358
359    use std::collections::HashMap;
360
361    #[test]
362    fn refarg() {
363        let c = Channel::get_private(BusType::Session).unwrap();
364        let m = Message::new_method_call(c.unique_name().unwrap(), "/mooh", "com.example.hello", "Hello").unwrap();
365
366        let mut vv: Vec<Variant<Box<dyn RefArg>>> = vec!();
367        vv.push(Variant(Box::new(5i32)));
368        vv.push(Variant(Box::new(String::from("Hello world"))));
369        let m = m.append_ref(&vv);
370
371        let (f1, f2) = (false, 7u64);
372        let mut v: Vec<&dyn RefArg> = vec!();
373        v.push(&f1);
374        v.push(&f2);
375        let m = m.append_ref(&v);
376        let vi32 = vec![7i32, 9i32];
377        let vstr: Vec<String> = ["This", "is", "dbus", "rs"].iter().map(|&s| s.into()).collect();
378        let m = m.append_ref(&[&vi32 as &dyn RefArg, &vstr as &dyn RefArg]);
379        let mut map = HashMap::new();
380        map.insert(true, String::from("Yes"));
381        map.insert(false, String::from("No"));
382        let m = m.append_ref(&[&map as &dyn RefArg, &1.5f64 as &dyn RefArg]);
383
384        c.send(m).unwrap();
385
386        loop {
387            if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() {
388                if m.msg_type() != MessageType::MethodCall { continue; }
389
390                let rv: Vec<Box<dyn RefArg + 'static>> = m.iter_init().collect();
391                println!("Receiving {:?}", rv);
392                let rv0: &Variant<Box<dyn RefArg>> = cast(&rv[0]).unwrap();
393                let rv00: &i32 = cast(&rv0.0).unwrap();
394                assert_eq!(rv00, &5i32);
395                assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>());
396                assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>());
397                assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>());
398                let mut diter = rv[6].as_iter().unwrap();
399                {
400                    let mut mmap: HashMap<bool, String> = HashMap::new();
401                    while let Some(k) = diter.next() {
402                        let x: String = diter.next().unwrap().as_str().unwrap().into();
403                        mmap.insert(*cast::<bool>(&k.box_clone()).unwrap(), x);
404                    }
405                    assert_eq!(mmap[&true], "Yes");
406                }
407                let mut iter = rv[6].as_iter().unwrap();
408                assert!(iter.next().unwrap().as_i64().is_some());
409                assert!(iter.next().unwrap().as_str().is_some());
410                assert!(iter.next().unwrap().as_str().is_none());
411                assert!(iter.next().unwrap().as_i64().is_none());
412                assert!(iter.next().is_none());
413                assert!(rv[7].as_f64().unwrap() > 1.0);
414                assert!(rv[7].as_f64().unwrap() < 2.0);
415                break;
416            }
417        }
418    }
419
420    #[test]
421    fn message_types() {
422        let c = Channel::get_private(BusType::Session).unwrap();
423
424        let m = Message::new_method_call(c.unique_name().unwrap(), "/hello", "com.example.hello", "Hello").unwrap();
425        let m = m.append1(2000u16);
426        let m = m.append1(&Array::new(&vec![129u8, 5, 254]));
427        let m = m.append2(Variant(&["Hello", "world"][..]), &[32768u16, 16u16, 12u16][..]);
428        let m = m.append3(-1i32, &*format!("Hello world"), -3.14f64);
429        let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64)));
430        let m = m.append2(Path::new("/a/valid/path").unwrap(), &Signature::new("a{sv}").unwrap());
431        let mut z = HashMap::new();
432        z.insert(123543u32, true);
433        z.insert(0u32, false);
434        let m = m.append1(Dict::new(&z));
435        let sending = format!("{:?}", m.iter_init());
436        println!("Sending {}", sending);
437        c.send(m).unwrap();
438
439        loop {
440            if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() {
441                if m.msg_type() != MessageType::MethodCall { continue; }
442                use super::Arg;
443                let receiving = format!("{:?}", m.iter_init());
444                println!("Receiving {}", receiving);
445                assert_eq!(sending, receiving);
446
447                assert_eq!(2000u16, m.get1().unwrap());
448                assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..])));
449                assert_eq!(m.read2::<u16, bool>().unwrap_err(),
450                    TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean });
451
452                let mut g = m.iter_init();
453                let e = g.read::<u32>().unwrap_err();
454                assert_eq!(e.pos(), 0);
455                assert_eq!(e.expected_arg_type(), ArgType::UInt32);
456                assert_eq!(e.found_arg_type(), ArgType::UInt16);
457
458                assert!(g.next() && g.next());
459                let v: Variant<Iter> = g.get().unwrap();
460                let mut viter = v.0;
461                assert_eq!(viter.arg_type(), Array::<&str,()>::ARG_TYPE);
462                let a: Array<&str, _> = viter.get().unwrap();
463                assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello", "world"]);
464
465                assert!(g.next());
466                assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16
467                assert!(g.next() && g.next() && g.next() && g.next());
468
469                assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64))));
470                assert!(g.next());
471                assert_eq!(g.get(), Some(Path::new("/a/valid/path").unwrap()));
472                assert!(g.next());
473                assert_eq!(g.get(), Some(Signature::new("a{sv}").unwrap()));
474                assert!(g.next());
475                let d: Dict<u32, bool, _> = g.get().unwrap();
476                let z2: HashMap<_, _> = d.collect();
477                assert_eq!(z, z2);
478                break;
479            }
480        }
481    }
482
483    #[test]
484    fn cast_vecs() {
485        let c = Channel::get_private(BusType::Session).unwrap();
486
487        let m = Message::new_method_call(c.unique_name().unwrap(), "/hello", "com.example.hello", "Hello").unwrap();
488        macro_rules! append_array {
489            ($m:expr, $t:ty) => {
490                $m.append1(Variant(&Array::<&$t, _>::new(&vec![Default::default()])))
491            };
492        }
493        let m = append_array!(m, bool);
494        let m = append_array!(m, u8);
495        let m = append_array!(m, u16);
496        let m = append_array!(m, i16);
497        let m = append_array!(m, u32);
498        let m = append_array!(m, i32);
499        let m = append_array!(m, f64);
500        let m = append_array!(m, String);
501        c.send(m).unwrap();
502        loop {
503            if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() {
504                if m.msg_type() != MessageType::MethodCall {
505                    continue;
506                }
507                let mut i = m.iter_init();
508                let mut i2 = m.iter_init();
509
510                macro_rules! check_array {
511                    ($t:ty) => {
512                        let array: Variant<Box<dyn RefArg>> = i.read().unwrap();
513                        assert_eq!(
514                            cast::<Vec<$t>>(&(array.0)),
515                            Some(&vec![Default::default()]),
516                            "a variant containing an array of {0} should be castable to a Vec<{0}>",
517                            std::any::type_name::<$t>()
518                        );
519                        let refarg = i2.get_refarg().unwrap();
520                        println!("refarg {:?}", refarg);
521                        let cloned = refarg.box_clone();
522                        println!("cloned: {:?}", cloned);
523                        let st_inner = refarg.as_static_inner(0).unwrap();
524                        println!("st_inner {:?}", st_inner);
525                        i2.next();
526                        assert_eq!(cast::<Vec<$t>>(st_inner), Some(&vec![Default::default()]));
527                        let cl_inner = refarg.as_static_inner(0).unwrap();
528                        assert_eq!(cast::<Vec<$t>>(cl_inner), Some(&vec![Default::default()]));
529                    };
530                }
531                check_array!(bool);
532                check_array!(u8);
533                check_array!(u16);
534                check_array!(i16);
535                check_array!(u32);
536                check_array!(i32);
537                check_array!(f64);
538                check_array!(String);
539                break;
540            }
541        }
542    }
543
544    #[test]
545    fn cast_dicts() {
546        let c = Channel::get_private(BusType::Session).unwrap();
547
548        let m = Message::new_method_call(
549            c.unique_name().unwrap(),
550            "/hello",
551            "com.example.hello",
552            "Hello",
553        )
554        .unwrap();
555        macro_rules! append_dict_variant {
556            ($m:expr, $k:ty, $v:ty) => {{
557                let mut map: HashMap<$k, Variant<Box<dyn RefArg>>> = HashMap::new();
558                map.insert(Default::default(), Variant(Box::new(<$v>::default())));
559                $m.append1(Variant(&map))
560            }};
561        }
562        let m = append_dict_variant!(m, bool, bool);
563        let m = append_dict_variant!(m, u8, u8);
564        let m = append_dict_variant!(m, u16, u16);
565        let m = append_dict_variant!(m, i16, i16);
566        let m = append_dict_variant!(m, u32, u32);
567        let m = append_dict_variant!(m, i32, i32);
568        let m = append_dict_variant!(m, u64, u64);
569        let m = append_dict_variant!(m, i64, i64);
570        let m = append_dict_variant!(m, u8, f64);
571        let m = append_dict_variant!(m, String, String);
572        c.send(m).unwrap();
573        loop {
574            if let Some(m) = c
575                .blocking_pop_message(std::time::Duration::from_millis(1000))
576                .unwrap()
577            {
578                if m.msg_type() != MessageType::MethodCall {
579                    continue;
580                }
581                let mut i = m.iter_init();
582                let mut i2 = m.iter_init();
583
584                macro_rules! check_dict_variant {
585                    ($k:ty, $v:ty) => {
586                        let map: Variant<Box<dyn RefArg>> = i.read().unwrap();
587                        let expected_key: $k = Default::default();
588                        let expected_value: $v = Default::default();
589                        let cast_map = cast::<HashMap<$k, Variant<Box<dyn RefArg>>>>(&map.0);
590                        assert!(cast_map.is_some(),
591                            "a variant containing a dict of {0} to Variant({1}) should be castable to a HashMap<{0}, Variant<Box<dyn RefArg>>>",
592                            std::any::type_name::<$k>(),
593                            std::any::type_name::<$v>()
594                        );
595                        let cast_map_value = cast_map.unwrap().get(&expected_key).unwrap();
596                        assert_eq!(
597                            cast::<$v>(&cast_map_value.0),
598                            Some(&expected_value),
599                            "a variant {0:?} containing a {1} should be castable to {1}",
600                            cast_map_value,
601                            std::any::type_name::<$v>()
602                        );
603                        let refarg = i2.get_refarg().unwrap();
604                        println!("refarg {:?}", refarg);
605                        let st_inner = refarg.as_static_inner(0).unwrap();
606                        println!("st_inner {:?}", st_inner);
607                        i2.next();
608                        assert!(cast::<HashMap<$k, Variant<Box<dyn RefArg>>>>(st_inner).is_some());
609                    };
610                }
611                check_dict_variant!(bool, bool);
612                check_dict_variant!(u8, u8);
613                check_dict_variant!(u16, u16);
614                check_dict_variant!(i16, i16);
615                check_dict_variant!(u32, u32);
616                check_dict_variant!(i32, i32);
617                check_dict_variant!(u64, u64);
618                check_dict_variant!(i64, i64);
619                check_dict_variant!(u8, f64);
620                check_dict_variant!(String, String);
621                break;
622            }
623        }
624    }
625}