1 | #![allow (dead_code)] |
2 | |
3 | use crate::{Signature, arg::TypeMismatchError, arg::Variant}; |
4 | use std::{fmt, any}; |
5 | use std::sync::Arc; |
6 | // use std::rc::Rc; |
7 | use std::collections::HashMap; |
8 | |
9 | use 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. |
14 | pub 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. |
22 | pub 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. |
31 | pub 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. |
40 | pub 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. |
46 | pub 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. |
52 | pub 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. |
59 | pub 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 | |
123 | impl<'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 ] |
131 | pub 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 ] |
141 | pub 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. |
144 | pub 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. |
151 | pub fn prop_cast<'a, T: 'static>(map: &'a PropMap, key: &str) -> Option<&'a T> { |
152 | map.get(key).and_then(|v: &Variant>| 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. |
159 | pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {} |
160 | |
161 | /// Types that can be used as keys in a dict type implement this trait. |
162 | pub trait DictKey: Arg {} |
163 | |
164 | |
165 | |
166 | /// Simple lift over reference to value - this makes some iterators more ergonomic to use |
167 | impl<'a, T: Arg> Arg for &'a T { |
168 | const ARG_TYPE: ArgType = T::ARG_TYPE; |
169 | fn signature() -> Signature<'static> { T::signature() } |
170 | } |
171 | impl<'a, T: Append> Append for &'a T { |
172 | fn append_by_ref(&self, i: &mut IterAppend) { (&**self).append_by_ref(i) } |
173 | } |
174 | impl<'a, T: DictKey> DictKey for &'a T {} |
175 | |
176 | impl<'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 | |
205 | macro_rules! deref_impl { |
206 | ($t: ident, $ss: ident, $make_mut: expr) => { |
207 | |
208 | impl<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 | } |
234 | impl<T: DictKey> DictKey for $t<T> {} |
235 | |
236 | impl<T: Arg> Arg for $t<T> { |
237 | const ARG_TYPE: ArgType = T::ARG_TYPE; |
238 | fn signature() -> Signature<'static> { T::signature() } |
239 | } |
240 | impl<'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 | |
247 | impl<T: Append> Append for Box<T> { |
248 | fn append_by_ref(&self, i: &mut IterAppend) { (&**self).append_by_ref(i) } |
249 | } |
250 | |
251 | deref_impl!(Box, self, &mut **self ); |
252 | // deref_impl!(Rc, self, Rc::get_mut(self).unwrap()); |
253 | deref_impl!(Arc, self, Arc::get_mut(self).unwrap()); |
254 | |
255 | macro_rules! argall_impl { |
256 | ($($n: ident $t: ident $s: ty,)+) => { |
257 | |
258 | impl<$($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 | |
266 | impl<$($t: Append),*> AppendAll for ($($t,)*) { |
267 | fn append(&self, ia: &mut IterAppend) { |
268 | let ( $($n,)*) = self; |
269 | $( ia.append($n); )* |
270 | } |
271 | } |
272 | |
273 | impl<$($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 | |
284 | impl ArgAll for () { |
285 | type strs = (); |
286 | fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(_: Self::strs, _: F) {} |
287 | } |
288 | |
289 | impl AppendAll for () { |
290 | fn append(&self, _: &mut IterAppend) {} |
291 | } |
292 | |
293 | impl ReadAll for () { |
294 | fn read(_: &mut Iter) -> Result<Self, TypeMismatchError> { |
295 | Ok(()) |
296 | } |
297 | } |
298 | |
299 | argall_impl!(a A str,); |
300 | argall_impl!(a A str, b B str,); |
301 | argall_impl!(a A str, b B str, c C str,); |
302 | argall_impl!(a A str, b B str, c C str, d D str,); |
303 | argall_impl!(a A str, b B str, c C str, d D str, e E str,); |
304 | argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str,); |
305 | argall_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str,); |
306 | argall_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,); |
307 | argall_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,); |
308 | argall_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,); |
309 | argall_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,); |
310 | argall_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,); |
311 | argall_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,); |
312 | argall_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,); |
313 | argall_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,); |
314 | argall_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,); |
315 | argall_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,); |
316 | argall_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,); |
317 | argall_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,); |
318 | argall_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,); |
319 | argall_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,); |
320 | argall_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,); |
321 | argall_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,); |
322 | argall_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,); |
323 | argall_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,); |
324 | |
325 | |
326 | #[cfg (test)] |
327 | mod test { |
328 | use crate::{channel::{Channel, BusType}, Message, Path, Signature}; |
329 | use crate::message::MessageType; |
330 | use crate::arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast}; |
331 | |
332 | use std::collections::HashMap; |
333 | |
334 | #[test ] |
335 | fn refarg() { |
336 | let c = Channel::get_private(BusType::Session).unwrap(); |
337 | let m = Message::new_method_call(c.unique_name().unwrap(), "/mooh" , "com.example.hello" , "Hello" ).unwrap(); |
338 | |
339 | let mut vv: Vec<Variant<Box<dyn RefArg>>> = vec!(); |
340 | vv.push(Variant(Box::new(5i32))); |
341 | vv.push(Variant(Box::new(String::from("Hello world" )))); |
342 | let m = m.append_ref(&vv); |
343 | |
344 | let (f1, f2) = (false, 7u64); |
345 | let mut v: Vec<&dyn RefArg> = vec!(); |
346 | v.push(&f1); |
347 | v.push(&f2); |
348 | let m = m.append_ref(&v); |
349 | let vi32 = vec![7i32, 9i32]; |
350 | let vstr: Vec<String> = ["This" , "is" , "dbus" , "rs" ].iter().map(|&s| s.into()).collect(); |
351 | let m = m.append_ref(&[&vi32 as &dyn RefArg, &vstr as &dyn RefArg]); |
352 | let mut map = HashMap::new(); |
353 | map.insert(true, String::from("Yes" )); |
354 | map.insert(false, String::from("No" )); |
355 | let m = m.append_ref(&[&map as &dyn RefArg, &1.5f64 as &dyn RefArg]); |
356 | |
357 | c.send(m).unwrap(); |
358 | |
359 | loop { |
360 | if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() { |
361 | if m.msg_type() != MessageType::MethodCall { continue; } |
362 | |
363 | let rv: Vec<Box<dyn RefArg + 'static>> = m.iter_init().collect(); |
364 | println!("Receiving {:?}" , rv); |
365 | let rv0: &Variant<Box<dyn RefArg>> = cast(&rv[0]).unwrap(); |
366 | let rv00: &i32 = cast(&rv0.0).unwrap(); |
367 | assert_eq!(rv00, &5i32); |
368 | assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>()); |
369 | assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>()); |
370 | assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>()); |
371 | let mut diter = rv[6].as_iter().unwrap(); |
372 | { |
373 | let mut mmap: HashMap<bool, String> = HashMap::new(); |
374 | while let Some(k) = diter.next() { |
375 | let x: String = diter.next().unwrap().as_str().unwrap().into(); |
376 | mmap.insert(*cast::<bool>(&k.box_clone()).unwrap(), x); |
377 | } |
378 | assert_eq!(mmap[&true], "Yes" ); |
379 | } |
380 | let mut iter = rv[6].as_iter().unwrap(); |
381 | assert!(iter.next().unwrap().as_i64().is_some()); |
382 | assert!(iter.next().unwrap().as_str().is_some()); |
383 | assert!(iter.next().unwrap().as_str().is_none()); |
384 | assert!(iter.next().unwrap().as_i64().is_none()); |
385 | assert!(iter.next().is_none()); |
386 | assert!(rv[7].as_f64().unwrap() > 1.0); |
387 | assert!(rv[7].as_f64().unwrap() < 2.0); |
388 | break; |
389 | } |
390 | } |
391 | } |
392 | |
393 | #[test ] |
394 | fn message_types() { |
395 | let c = Channel::get_private(BusType::Session).unwrap(); |
396 | |
397 | let m = Message::new_method_call(c.unique_name().unwrap(), "/hello" , "com.example.hello" , "Hello" ).unwrap(); |
398 | let m = m.append1(2000u16); |
399 | let m = m.append1(&Array::new(&vec![129u8, 5, 254])); |
400 | let m = m.append2(Variant(&["Hello" , "world" ][..]), &[32768u16, 16u16, 12u16][..]); |
401 | let m = m.append3(-1i32, &*format!("Hello world" ), -3.14f64); |
402 | let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64))); |
403 | let m = m.append2(Path::new("/a/valid/path" ).unwrap(), &Signature::new("a{sv}" ).unwrap()); |
404 | let mut z = HashMap::new(); |
405 | z.insert(123543u32, true); |
406 | z.insert(0u32, false); |
407 | let m = m.append1(Dict::new(&z)); |
408 | let sending = format!("{:?}" , m.iter_init()); |
409 | println!("Sending {}" , sending); |
410 | c.send(m).unwrap(); |
411 | |
412 | loop { |
413 | if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() { |
414 | if m.msg_type() != MessageType::MethodCall { continue; } |
415 | use super::Arg; |
416 | let receiving = format!("{:?}" , m.iter_init()); |
417 | println!("Receiving {}" , receiving); |
418 | assert_eq!(sending, receiving); |
419 | |
420 | assert_eq!(2000u16, m.get1().unwrap()); |
421 | assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..]))); |
422 | assert_eq!(m.read2::<u16, bool>().unwrap_err(), |
423 | TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean }); |
424 | |
425 | let mut g = m.iter_init(); |
426 | let e = g.read::<u32>().unwrap_err(); |
427 | assert_eq!(e.pos(), 0); |
428 | assert_eq!(e.expected_arg_type(), ArgType::UInt32); |
429 | assert_eq!(e.found_arg_type(), ArgType::UInt16); |
430 | |
431 | assert!(g.next() && g.next()); |
432 | let v: Variant<Iter> = g.get().unwrap(); |
433 | let mut viter = v.0; |
434 | assert_eq!(viter.arg_type(), Array::<&str,()>::ARG_TYPE); |
435 | let a: Array<&str, _> = viter.get().unwrap(); |
436 | assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello" , "world" ]); |
437 | |
438 | assert!(g.next()); |
439 | assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16 |
440 | assert!(g.next() && g.next() && g.next() && g.next()); |
441 | |
442 | assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64)))); |
443 | assert!(g.next()); |
444 | assert_eq!(g.get(), Some(Path::new("/a/valid/path" ).unwrap())); |
445 | assert!(g.next()); |
446 | assert_eq!(g.get(), Some(Signature::new("a{sv}" ).unwrap())); |
447 | assert!(g.next()); |
448 | let d: Dict<u32, bool, _> = g.get().unwrap(); |
449 | let z2: HashMap<_, _> = d.collect(); |
450 | assert_eq!(z, z2); |
451 | break; |
452 | } |
453 | } |
454 | } |
455 | |
456 | #[test ] |
457 | fn cast_vecs() { |
458 | let c = Channel::get_private(BusType::Session).unwrap(); |
459 | |
460 | let m = Message::new_method_call(c.unique_name().unwrap(), "/hello" , "com.example.hello" , "Hello" ).unwrap(); |
461 | macro_rules! append_array { |
462 | ($m:expr, $t:ty) => { |
463 | $m.append1(Variant(&Array::<&$t, _>::new(&vec![Default::default()]))) |
464 | }; |
465 | } |
466 | let m = append_array!(m, bool); |
467 | let m = append_array!(m, u8); |
468 | let m = append_array!(m, u16); |
469 | let m = append_array!(m, i16); |
470 | let m = append_array!(m, u32); |
471 | let m = append_array!(m, i32); |
472 | let m = append_array!(m, f64); |
473 | let m = append_array!(m, String); |
474 | c.send(m).unwrap(); |
475 | loop { |
476 | if let Some(m) = c.blocking_pop_message(std::time::Duration::from_millis(1000)).unwrap() { |
477 | if m.msg_type() != MessageType::MethodCall { |
478 | continue; |
479 | } |
480 | let mut i = m.iter_init(); |
481 | let mut i2 = m.iter_init(); |
482 | |
483 | macro_rules! check_array { |
484 | ($t:ty) => { |
485 | let array: Variant<Box<dyn RefArg>> = i.read().unwrap(); |
486 | assert_eq!( |
487 | cast::<Vec<$t>>(&(array.0)), |
488 | Some(&vec![Default::default()]), |
489 | "a variant containing an array of {0} should be castable to a Vec<{0}>" , |
490 | std::any::type_name::<$t>() |
491 | ); |
492 | let refarg = i2.get_refarg().unwrap(); |
493 | println!("refarg {:?}" , refarg); |
494 | let cloned = refarg.box_clone(); |
495 | println!("cloned: {:?}" , cloned); |
496 | let st_inner = refarg.as_static_inner(0).unwrap(); |
497 | println!("st_inner {:?}" , st_inner); |
498 | i2.next(); |
499 | assert_eq!(cast::<Vec<$t>>(st_inner), Some(&vec![Default::default()])); |
500 | let cl_inner = refarg.as_static_inner(0).unwrap(); |
501 | assert_eq!(cast::<Vec<$t>>(cl_inner), Some(&vec![Default::default()])); |
502 | }; |
503 | } |
504 | check_array!(bool); |
505 | check_array!(u8); |
506 | check_array!(u16); |
507 | check_array!(i16); |
508 | check_array!(u32); |
509 | check_array!(i32); |
510 | check_array!(f64); |
511 | check_array!(String); |
512 | break; |
513 | } |
514 | } |
515 | } |
516 | |
517 | #[test ] |
518 | fn cast_dicts() { |
519 | let c = Channel::get_private(BusType::Session).unwrap(); |
520 | |
521 | let m = Message::new_method_call( |
522 | c.unique_name().unwrap(), |
523 | "/hello" , |
524 | "com.example.hello" , |
525 | "Hello" , |
526 | ) |
527 | .unwrap(); |
528 | macro_rules! append_dict_variant { |
529 | ($m:expr, $k:ty, $v:ty) => {{ |
530 | let mut map: HashMap<$k, Variant<Box<dyn RefArg>>> = HashMap::new(); |
531 | map.insert(Default::default(), Variant(Box::new(<$v>::default()))); |
532 | $m.append1(Variant(&map)) |
533 | }}; |
534 | } |
535 | let m = append_dict_variant!(m, bool, bool); |
536 | let m = append_dict_variant!(m, u8, u8); |
537 | let m = append_dict_variant!(m, u16, u16); |
538 | let m = append_dict_variant!(m, i16, i16); |
539 | let m = append_dict_variant!(m, u32, u32); |
540 | let m = append_dict_variant!(m, i32, i32); |
541 | let m = append_dict_variant!(m, u64, u64); |
542 | let m = append_dict_variant!(m, i64, i64); |
543 | let m = append_dict_variant!(m, u8, f64); |
544 | let m = append_dict_variant!(m, String, String); |
545 | c.send(m).unwrap(); |
546 | loop { |
547 | if let Some(m) = c |
548 | .blocking_pop_message(std::time::Duration::from_millis(1000)) |
549 | .unwrap() |
550 | { |
551 | if m.msg_type() != MessageType::MethodCall { |
552 | continue; |
553 | } |
554 | let mut i = m.iter_init(); |
555 | let mut i2 = m.iter_init(); |
556 | |
557 | macro_rules! check_dict_variant { |
558 | ($k:ty, $v:ty) => { |
559 | let map: Variant<Box<dyn RefArg>> = i.read().unwrap(); |
560 | let expected_key: $k = Default::default(); |
561 | let expected_value: $v = Default::default(); |
562 | let cast_map = cast::<HashMap<$k, Variant<Box<dyn RefArg>>>>(&map.0); |
563 | assert!(cast_map.is_some(), |
564 | "a variant containing a dict of {0} to Variant({1}) should be castable to a HashMap<{0}, Variant<Box<dyn RefArg>>>" , |
565 | std::any::type_name::<$k>(), |
566 | std::any::type_name::<$v>() |
567 | ); |
568 | let cast_map_value = cast_map.unwrap().get(&expected_key).unwrap(); |
569 | assert_eq!( |
570 | cast::<$v>(&cast_map_value.0), |
571 | Some(&expected_value), |
572 | "a variant {0:?} containing a {1} should be castable to {1}" , |
573 | cast_map_value, |
574 | std::any::type_name::<$v>() |
575 | ); |
576 | let refarg = i2.get_refarg().unwrap(); |
577 | println!("refarg {:?}" , refarg); |
578 | let st_inner = refarg.as_static_inner(0).unwrap(); |
579 | println!("st_inner {:?}" , st_inner); |
580 | i2.next(); |
581 | assert!(cast::<HashMap<$k, Variant<Box<dyn RefArg>>>>(st_inner).is_some()); |
582 | }; |
583 | } |
584 | check_dict_variant!(bool, bool); |
585 | check_dict_variant!(u8, u8); |
586 | check_dict_variant!(u16, u16); |
587 | check_dict_variant!(i16, i16); |
588 | check_dict_variant!(u32, u32); |
589 | check_dict_variant!(i32, i32); |
590 | check_dict_variant!(u64, u64); |
591 | check_dict_variant!(i64, i64); |
592 | check_dict_variant!(u8, f64); |
593 | check_dict_variant!(String, String); |
594 | break; |
595 | } |
596 | } |
597 | } |
598 | } |
599 | |