| 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 | |