| 1 | use super::*; |
| 2 | use crate::{Message, ffi}; |
| 3 | use crate::strings::{Signature, Path}; |
| 4 | use std::marker::PhantomData; |
| 5 | use std::{ptr, mem, any, fmt}; |
| 6 | use super::check; |
| 7 | use std::ffi::{CString}; |
| 8 | use std::os::raw::{c_void, c_int}; |
| 9 | use std::collections::{HashMap, BTreeMap}; |
| 10 | use std::hash::{Hash, BuildHasher}; |
| 11 | |
| 12 | // Map DBus-Type -> Alignment. Copied from _dbus_marshal_write_fixed_multi in |
| 13 | // http://dbus.freedesktop.org/doc/api/html/dbus-marshal-basic_8c_source.html#l01020 |
| 14 | // Note that Rust booleans are one byte, dbus booleans are four bytes! |
| 15 | const FIXED_ARRAY_ALIGNMENTS: [(ArgType, usize); 9] = [ |
| 16 | (ArgType::Byte, 1), |
| 17 | (ArgType::Int16, 2), |
| 18 | (ArgType::UInt16, 2), |
| 19 | (ArgType::UInt32, 4), |
| 20 | (ArgType::Int32, 4), |
| 21 | (ArgType::Boolean, 4), |
| 22 | (ArgType::Int64, 8), |
| 23 | (ArgType::UInt64, 8), |
| 24 | (ArgType::Double, 8) |
| 25 | ]; |
| 26 | |
| 27 | /// Represents a D-Bus array. |
| 28 | impl<'a, T: Arg> Arg for &'a [T] { |
| 29 | const ARG_TYPE: ArgType = ArgType::Array; |
| 30 | fn signature() -> Signature<'static> { Signature::from(format!("a{}" , T::signature())) } |
| 31 | } |
| 32 | |
| 33 | fn array_append<T: Arg, F: FnMut(&T, &mut IterAppend)>(z: &[T], i: &mut IterAppend, mut f: F) { |
| 34 | let zptr: *const T = z.as_ptr(); |
| 35 | let zlen: i32 = z.len() as i32; |
| 36 | |
| 37 | // Can we do append_fixed_array? |
| 38 | let a: (ArgType, {unknown}) = (T::ARG_TYPE, mem::size_of::<T>()); |
| 39 | let can_fixed_array: bool = (zlen > 1) && (z.len() == zlen as usize) && FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == a); |
| 40 | |
| 41 | i.append_container(ArgType::Array, sig:Some(T::signature().as_cstr()), |s| |
| 42 | if can_fixed_array { unsafe { check(f:"dbus_message_iter_append_fixed_array" , |
| 43 | i:ffi::dbus_message_iter_append_fixed_array(&mut s.0, element_type:a.0 as c_int, &zptr as *const _ as *const c_void, n_elements:zlen)) }} |
| 44 | else { for arg: &T in z { f(arg, s); }} |
| 45 | ); |
| 46 | } |
| 47 | |
| 48 | /// Appends a D-Bus array. Note: In case you have a large array of a type that implements FixedArray, |
| 49 | /// using this method will be more efficient than using an Array. |
| 50 | impl<'a, T: Arg + Append + Clone> Append for &'a [T] { |
| 51 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 52 | array_append(self, i, |arg, s: &mut IterAppend<'_>| arg.clone().append(s)); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | impl<'a, T: Arg + RefArg> RefArg for &'a [T] { |
| 57 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 58 | fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}" , <T as Arg>::signature())) } |
| 59 | fn append(&self, i: &mut IterAppend) { |
| 60 | array_append(self, i, |arg: &{unknown}, s: &mut IterAppend<'_>| RefArg::append(self:arg,s)); |
| 61 | } |
| 62 | #[inline ] |
| 63 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 64 | #[inline ] |
| 65 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 66 | #[inline ] |
| 67 | fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { |
| 68 | self.get(index).map(|x: &T| x as &dyn RefArg) |
| 69 | } |
| 70 | |
| 71 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 72 | T::array_clone(self).unwrap_or_else(|| { |
| 73 | Box::new(InternalArray { |
| 74 | inner_sig: <T as Arg>::signature(), |
| 75 | data: self.iter().map(|x| x.box_clone()).collect(), |
| 76 | }) |
| 77 | }) |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | impl<T: Arg + RefArg> RefArg for Vec<T> { |
| 82 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 83 | fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}" , <T as Arg>::signature())) } |
| 84 | fn append(&self, i: &mut IterAppend) { |
| 85 | array_append(&self, i, |arg: &{unknown}, s: &mut IterAppend<'_>| RefArg::append(self:arg,s)); |
| 86 | } |
| 87 | #[inline ] |
| 88 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 89 | #[inline ] |
| 90 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 91 | fn as_iter<'a>(&'a self) -> Option<Box<dyn Iterator<Item=&'a dyn RefArg> + 'a>> { |
| 92 | Some(Box::new(self.iter().map(|b| b as &dyn RefArg))) |
| 93 | } |
| 94 | #[inline ] |
| 95 | fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { |
| 96 | self.get(index).map(|x| x as &dyn RefArg) |
| 97 | } |
| 98 | #[inline ] |
| 99 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { (&**self).box_clone() } |
| 100 | } |
| 101 | |
| 102 | |
| 103 | impl<'a, T: FixedArray> Get<'a> for &'a [T] { |
| 104 | fn get(i: &mut Iter<'a>) -> Option<&'a [T]> { |
| 105 | debug_assert!(FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == (T::ARG_TYPE, mem::size_of::<T>()))); |
| 106 | i.recurse(Self::ARG_TYPE).and_then(|mut si| unsafe { |
| 107 | let etype = ffi::dbus_message_iter_get_element_type(&mut i.0); |
| 108 | |
| 109 | if etype != T::ARG_TYPE as c_int { return None }; |
| 110 | |
| 111 | let mut v: *mut T = ptr::null_mut(); |
| 112 | let mut i: i32 = 0; |
| 113 | ffi::dbus_message_iter_get_fixed_array(&mut si.0, &mut v as *mut _ as *mut c_void, &mut i); |
| 114 | if v.is_null() { |
| 115 | assert_eq!(i, 0); |
| 116 | Some(&[][..]) |
| 117 | } else { |
| 118 | Some(::std::slice::from_raw_parts(v, i as usize)) |
| 119 | } |
| 120 | }) |
| 121 | } |
| 122 | } |
| 123 | |
| 124 | |
| 125 | #[derive(Copy, Clone, Debug)] |
| 126 | /// Append a D-Bus dict type (i e, an array of dict entries). |
| 127 | /// |
| 128 | /// See the argument guide and module level documentation for details and alternatives. |
| 129 | pub struct Dict<'a, K: DictKey, V: Arg, I>(I, PhantomData<(&'a Message, *const K, *const V)>); |
| 130 | |
| 131 | impl<'a, K: DictKey, V: Arg, I> Dict<'a, K, V, I> { |
| 132 | fn entry_sig() -> String { format!("{{{}{}}}" , K::signature(), V::signature()) } |
| 133 | } |
| 134 | |
| 135 | impl<'a, K: 'a + DictKey, V: 'a + Append + Arg, I: Iterator<Item=(K, V)>> Dict<'a, K, V, I> { |
| 136 | /// Creates a new Dict from an iterator. |
| 137 | pub fn new<J: IntoIterator<IntoIter=I, Item=(K, V)>>(j: J) -> Dict<'a, K, V, I> { Dict(j.into_iter(), PhantomData) } |
| 138 | } |
| 139 | |
| 140 | impl<'a, K: DictKey, V: Arg, I> Arg for Dict<'a, K, V, I> { |
| 141 | const ARG_TYPE: ArgType = ArgType::Array; |
| 142 | fn signature() -> Signature<'static> { |
| 143 | Signature::from(format!("a{}" , Self::entry_sig())) } |
| 144 | } |
| 145 | |
| 146 | impl<'a, K: 'a + DictKey + Append, V: 'a + Append + Arg, I: Iterator<Item=(K, V)> + Clone> Append for Dict<'a, K, V, I> { |
| 147 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 148 | let z = self.0.clone(); |
| 149 | i.append_container(Self::ARG_TYPE, sig:Some(&CString::new(Self::entry_sig()).unwrap()), |s| for (k, v) in z { |
| 150 | s.append_container(ArgType::DictEntry, None, |ss: &mut IterAppend<'_>| { |
| 151 | k.append_by_ref(ss); |
| 152 | v.append_by_ref(ss); |
| 153 | }) |
| 154 | }); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | |
| 159 | impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Get<'a> for Dict<'a, K, V, Iter<'a>> { |
| 160 | fn get(i: &mut Iter<'a>) -> Option<Self> { |
| 161 | i.recurse(Self::ARG_TYPE).map(|si| Dict(si, PhantomData)) |
| 162 | // TODO: Verify full element signature? |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Iterator for Dict<'a, K, V, Iter<'a>> { |
| 167 | type Item = (K, V); |
| 168 | fn next(&mut self) -> Option<(K, V)> { |
| 169 | let i = self.0.recurse(ArgType::DictEntry).and_then(|mut si| { |
| 170 | let k = si.get(); |
| 171 | if k.is_none() { return None }; |
| 172 | assert!(si.next()); |
| 173 | let v = si.get(); |
| 174 | if v.is_none() { return None }; |
| 175 | Some((k.unwrap(), v.unwrap())) |
| 176 | }); |
| 177 | self.0.next(); |
| 178 | i |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | impl<K: DictKey, V: Arg, S: BuildHasher> Arg for HashMap<K, V, S> { |
| 183 | const ARG_TYPE: ArgType = ArgType::Array; |
| 184 | fn signature() -> Signature<'static> { |
| 185 | Signature::from(format!("a{{{}{}}}" , K::signature(), V::signature())) } |
| 186 | } |
| 187 | |
| 188 | impl<K: DictKey + Append + Eq + Hash, V: Arg + Append, S: BuildHasher> Append for HashMap<K, V, S> { |
| 189 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 190 | Dict::new(self.iter()).append_by_ref(i); |
| 191 | } |
| 192 | } |
| 193 | |
| 194 | impl<'a, K: DictKey + Get<'a> + Eq + Hash, V: Arg + Get<'a>, S: BuildHasher + Default> Get<'a> for HashMap<K, V, S> { |
| 195 | fn get(i: &mut Iter<'a>) -> Option<Self> { |
| 196 | // TODO: Full element signature is not verified. |
| 197 | Dict::get(i).map(|d| d.collect()) |
| 198 | } |
| 199 | } |
| 200 | |
| 201 | impl<K: DictKey + RefArg + Eq + Hash, V: RefArg + Arg, S: BuildHasher + Send + Sync> RefArg for HashMap<K, V, S> { |
| 202 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 203 | fn signature(&self) -> Signature<'static> { format!("a{{{}{}}}" , <K as Arg>::signature(), <V as Arg>::signature()).into() } |
| 204 | fn append(&self, i: &mut IterAppend) { |
| 205 | let sig = CString::new(format!("{{{}{}}}" , <K as Arg>::signature(), <V as Arg>::signature())).unwrap(); |
| 206 | i.append_container(ArgType::Array, Some(&sig), |s| for (k, v) in self { |
| 207 | s.append_container(ArgType::DictEntry, None, |ss| { |
| 208 | k.append(ss); |
| 209 | v.append(ss); |
| 210 | }) |
| 211 | }); |
| 212 | } |
| 213 | #[inline ] |
| 214 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 215 | #[inline ] |
| 216 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 217 | fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item=&'b dyn RefArg> + 'b>> { |
| 218 | Some(Box::new(self.iter().flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()))) |
| 219 | } |
| 220 | #[inline ] |
| 221 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 222 | Box::new(InternalDict { |
| 223 | outer_sig: self.signature(), |
| 224 | data: self.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(), |
| 225 | }) |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | impl<K: DictKey, V: Arg> Arg for BTreeMap<K, V> { |
| 230 | const ARG_TYPE: ArgType = ArgType::Array; |
| 231 | fn signature() -> Signature<'static> { |
| 232 | Signature::from(format!("a{{{}{}}}" , K::signature(), V::signature())) } |
| 233 | } |
| 234 | |
| 235 | impl<K: DictKey + Append + Eq + Ord, V: Arg + Append> Append for BTreeMap<K, V> { |
| 236 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 237 | Dict::new(self.iter()).append_by_ref(i); |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | impl<'a, K: DictKey + Get<'a> + Eq + Ord, V: Arg + Get<'a>> Get<'a> for BTreeMap<K, V> { |
| 242 | fn get(i: &mut Iter<'a>) -> Option<Self> { |
| 243 | // TODO: Full element signature is not verified. |
| 244 | Dict::get(i).map(|d| d.collect()) |
| 245 | } |
| 246 | } |
| 247 | |
| 248 | impl<K: DictKey + RefArg + Eq + Ord, V: RefArg + Arg> RefArg for BTreeMap<K, V> { |
| 249 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 250 | fn signature(&self) -> Signature<'static> { format!("a{{{}{}}}" , <K as Arg>::signature(), <V as Arg>::signature()).into() } |
| 251 | fn append(&self, i: &mut IterAppend) { |
| 252 | let sig = CString::new(format!("{{{}{}}}" , <K as Arg>::signature(), <V as Arg>::signature())).unwrap(); |
| 253 | i.append_container(ArgType::Array, Some(&sig), |s| for (k, v) in self { |
| 254 | s.append_container(ArgType::DictEntry, None, |ss| { |
| 255 | k.append(ss); |
| 256 | v.append(ss); |
| 257 | }) |
| 258 | }); |
| 259 | } |
| 260 | #[inline ] |
| 261 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 262 | #[inline ] |
| 263 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 264 | fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item=&'b dyn RefArg> + 'b>> { |
| 265 | Some(Box::new(self.iter().flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()))) |
| 266 | } |
| 267 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 268 | Box::new(InternalDict { |
| 269 | outer_sig: self.signature(), |
| 270 | data: self.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(), |
| 271 | }) |
| 272 | } |
| 273 | } |
| 274 | |
| 275 | |
| 276 | impl<T: Arg> Arg for Vec<T> { |
| 277 | const ARG_TYPE: ArgType = ArgType::Array; |
| 278 | fn signature() -> Signature<'static> { Signature::from(format!("a{}" , T::signature())) } |
| 279 | } |
| 280 | |
| 281 | impl<T: Arg + Append> Append for Vec<T> { |
| 282 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 283 | Array::new(self).append_by_ref(i); |
| 284 | } |
| 285 | } |
| 286 | |
| 287 | impl<'a, T: Arg + Get<'a>> Get<'a> for Vec<T> { |
| 288 | fn get(i: &mut Iter<'a>) -> Option<Self> { |
| 289 | <Array<T, Iter<'a>>>::get(i).map(|a| a.collect()) |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | |
| 294 | #[derive(Copy, Clone, Debug)] |
| 295 | /// Represents a D-Bus Array. Maximum flexibility (wraps an iterator of items to append). |
| 296 | /// |
| 297 | /// See the argument guide and module level documentation for details and alternatives. |
| 298 | pub struct Array<'a, T, I>(I, PhantomData<(fn() -> T, &'a ())>); |
| 299 | |
| 300 | impl<'a, T: 'a, I: Iterator<Item=T>> Array<'a, T, I> { |
| 301 | /// Creates a new Array from an iterator. |
| 302 | pub fn new<J: IntoIterator<IntoIter=I, Item=T>>(j: J) -> Array<'a, T, I> { Array(j.into_iter(), PhantomData) } |
| 303 | } |
| 304 | |
| 305 | impl<'a, T: Arg, I> Arg for Array<'a, T, I> { |
| 306 | const ARG_TYPE: ArgType = ArgType::Array; |
| 307 | fn signature() -> Signature<'static> { Signature::from(format!("a{}" , T::signature())) } |
| 308 | } |
| 309 | |
| 310 | impl<'a, T: 'a + Arg + Append, I: Iterator<Item=T> + Clone> Append for Array<'a, T, I> { |
| 311 | fn append_by_ref(&self, i: &mut IterAppend) { |
| 312 | let z = self.0.clone(); |
| 313 | i.append_container(ArgType::Array, sig:Some(T::signature().as_cstr()), |s: &mut IterAppend<'_>| for arg in z { arg.append_by_ref(s) }); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | impl<'a, T: Arg + Get<'a>> Get<'a> for Array<'a, T, Iter<'a>> { |
| 318 | fn get(i: &mut Iter<'a>) -> Option<Array<'a, T, Iter<'a>>> { |
| 319 | i.recurse(Self::ARG_TYPE).map(|si| Array(si, PhantomData)) |
| 320 | // TODO: Verify full element signature? |
| 321 | } |
| 322 | } |
| 323 | |
| 324 | impl<'a, T: Get<'a>> Iterator for Array<'a, T, Iter<'a>> { |
| 325 | type Item = T; |
| 326 | fn next(&mut self) -> Option<T> { |
| 327 | let i = self.0.get(); |
| 328 | self.0.next(); |
| 329 | i |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | // Due to the strong typing here; RefArg is implemented only for T's that are both Arg and RefArg. |
| 334 | // We need Arg for this to work for empty arrays (we can't get signature from first element if there is no elements). |
| 335 | // We need RefArg for box_clone. |
| 336 | impl<'a, T, I> RefArg for Array<'static, T, I> |
| 337 | where |
| 338 | T: 'a + Arg + RefArg, |
| 339 | I: fmt::Debug + Clone + Send + Sync + Iterator<Item=&'a T> |
| 340 | { |
| 341 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 342 | fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}" , <T as Arg>::signature())) } |
| 343 | fn append(&self, i: &mut IterAppend) { |
| 344 | let z = self.0.clone(); |
| 345 | i.append_container(ArgType::Array, sig:Some(<T as Arg>::signature().as_cstr()), |s: &mut IterAppend<'_>| |
| 346 | for arg: &{unknown} in z { RefArg::append(self:arg, s); } |
| 347 | ); |
| 348 | } |
| 349 | #[inline ] |
| 350 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 351 | #[inline ] |
| 352 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 353 | |
| 354 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 355 | Box::new(InternalArray { |
| 356 | inner_sig: <T as Arg>::signature(), |
| 357 | data: self.0.clone().map(|x| x.box_clone()).collect(), |
| 358 | }) |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | fn get_fixed_array_refarg<T: FixedArray + Clone + RefArg>(i: &mut Iter) -> Box<dyn RefArg> { |
| 363 | let s = <&[T]>::get(i).unwrap(); |
| 364 | Box::new(s.to_vec()) |
| 365 | } |
| 366 | |
| 367 | fn get_var_array_refarg<'a, T: 'static + RefArg + Arg, F: FnMut(&mut Iter<'a>) -> Option<T>> |
| 368 | (i: &mut Iter<'a>, mut f: F) -> Box<dyn RefArg> { |
| 369 | let mut v: Vec<T> = vec!(); // dbus_message_iter_get_element_count might be O(n), better not use it |
| 370 | let mut si = i.recurse(ArgType::Array).unwrap(); |
| 371 | while let Some(q) = f(&mut si) { v.push(q); si.next(); } |
| 372 | Box::new(v) |
| 373 | } |
| 374 | |
| 375 | fn get_dict_refarg<'a, K, V, KF, VF>(i: &mut Iter<'a>, mut kf: KF, mut vf: VF) -> Box<dyn RefArg> |
| 376 | where |
| 377 | K: DictKey + 'static + RefArg + Clone + Eq + Hash, |
| 378 | V: RefArg + Arg + 'static, |
| 379 | KF: FnMut(&mut Iter<'a>) -> Option<K>, |
| 380 | VF: FnMut(&mut Iter<'a>) -> Option<V>, |
| 381 | { |
| 382 | let mut data: HashMap<K, V> = HashMap::new(); |
| 383 | let mut si = i.recurse(ArgType::Array).unwrap(); |
| 384 | while let Some(mut d) = si.recurse(ArgType::DictEntry) { |
| 385 | let k: K = kf(&mut d).unwrap(); |
| 386 | d.next(); |
| 387 | let v: V = vf(&mut d).unwrap(); |
| 388 | data.insert(k, v); |
| 389 | si.next(); |
| 390 | } |
| 391 | Box::new(data) |
| 392 | } |
| 393 | |
| 394 | #[derive(Debug)] |
| 395 | struct InternalDict<K> { |
| 396 | data: Vec<(K, Box<dyn RefArg>)>, |
| 397 | outer_sig: Signature<'static>, |
| 398 | } |
| 399 | |
| 400 | fn get_internal_dict_refarg<'a, K, F: FnMut(&mut Iter<'a>) -> Option<K>>( |
| 401 | i: &mut Iter<'a>, |
| 402 | mut f: F, |
| 403 | ) -> Box<dyn RefArg> |
| 404 | where |
| 405 | K: DictKey + 'static + RefArg + Clone, |
| 406 | { |
| 407 | let mut data = vec![]; |
| 408 | let outer_sig: Signature<'static> = i.signature(); |
| 409 | let mut si = i.recurse(ArgType::Array).unwrap(); |
| 410 | while let Some(mut d) = si.recurse(ArgType::DictEntry) { |
| 411 | let k = f(&mut d).unwrap(); |
| 412 | d.next(); |
| 413 | data.push((k, d.get_refarg().unwrap())); |
| 414 | si.next(); |
| 415 | } |
| 416 | Box::new(InternalDict { data, outer_sig }) |
| 417 | } |
| 418 | |
| 419 | // This only happens from box_clone |
| 420 | impl RefArg for InternalDict<Box<dyn RefArg>> { |
| 421 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 422 | fn signature(&self) -> Signature<'static> { self.outer_sig.clone() } |
| 423 | fn append(&self, i: &mut IterAppend) { |
| 424 | let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..]; |
| 425 | let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap(); |
| 426 | i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data { |
| 427 | s.append_container(ArgType::DictEntry, None, |ss| { |
| 428 | k.append(ss); |
| 429 | v.append(ss); |
| 430 | }) |
| 431 | }); |
| 432 | } |
| 433 | #[inline ] |
| 434 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 435 | #[inline ] |
| 436 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 437 | fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item=&'b dyn RefArg> + 'b>> { |
| 438 | Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()))) |
| 439 | } |
| 440 | fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { |
| 441 | let (k, v) = self.data.get(index / 2)?; |
| 442 | Some(if index & 1 != 0 { v } else { k }) |
| 443 | } |
| 444 | #[inline ] |
| 445 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 446 | Box::new(InternalDict { |
| 447 | data: self.data.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(), |
| 448 | outer_sig: self.outer_sig.clone(), |
| 449 | }) |
| 450 | } |
| 451 | } |
| 452 | |
| 453 | |
| 454 | impl<K: DictKey + RefArg + Clone + 'static> RefArg for InternalDict<K> { |
| 455 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 456 | fn signature(&self) -> Signature<'static> { self.outer_sig.clone() } |
| 457 | fn append(&self, i: &mut IterAppend) { |
| 458 | let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..]; |
| 459 | let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap(); |
| 460 | i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data { |
| 461 | s.append_container(ArgType::DictEntry, None, |ss| { |
| 462 | k.append(ss); |
| 463 | v.append(ss); |
| 464 | }) |
| 465 | }); |
| 466 | } |
| 467 | #[inline ] |
| 468 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 469 | #[inline ] |
| 470 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 471 | fn as_iter<'b>(&'b self) -> Option<Box<dyn Iterator<Item=&'b dyn RefArg> + 'b>> { |
| 472 | Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &dyn RefArg, v as &dyn RefArg].into_iter()))) |
| 473 | } |
| 474 | fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { |
| 475 | let (k, v) = self.data.get(index / 2)?; |
| 476 | Some(if index & 1 != 0 { v } else { k }) |
| 477 | } |
| 478 | #[inline ] |
| 479 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 480 | Box::new(InternalDict { |
| 481 | data: self.data.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(), |
| 482 | outer_sig: self.outer_sig.clone(), |
| 483 | }) |
| 484 | } |
| 485 | } |
| 486 | |
| 487 | |
| 488 | // Fallback for Arrays of Arrays and Arrays of Structs. |
| 489 | // We store the signature manually here and promise that it is correct for all elements |
| 490 | // has that signature. |
| 491 | #[derive(Debug)] |
| 492 | struct InternalArray { |
| 493 | data: Vec<Box<dyn RefArg>>, |
| 494 | inner_sig: Signature<'static>, |
| 495 | } |
| 496 | |
| 497 | fn get_internal_array(i: &mut Iter) -> Box<dyn RefArg> { |
| 498 | let mut si = i.recurse(ArgType::Array).unwrap(); |
| 499 | let inner_sig: Signature<'static> = si.signature(); |
| 500 | let data = si.collect::<Vec<_>>(); |
| 501 | Box::new(InternalArray { data, inner_sig }) |
| 502 | } |
| 503 | |
| 504 | impl RefArg for InternalArray { |
| 505 | fn arg_type(&self) -> ArgType { ArgType::Array } |
| 506 | fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}" , self.inner_sig)) } |
| 507 | fn append(&self, i: &mut IterAppend) { |
| 508 | i.append_container(ArgType::Array, Some(self.inner_sig.as_cstr()), |s| |
| 509 | for arg in &self.data { RefArg::append(arg,s) } |
| 510 | ); |
| 511 | } |
| 512 | #[inline ] |
| 513 | fn as_any(&self) -> &dyn any::Any where Self: 'static { self } |
| 514 | #[inline ] |
| 515 | fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self } |
| 516 | fn as_iter<'a>(&'a self) -> Option<Box<dyn Iterator<Item=&'a dyn RefArg> + 'a>> { |
| 517 | Some(Box::new(self.data.iter().map(|b| b as &dyn RefArg))) |
| 518 | } |
| 519 | fn as_static_inner(&self, index: usize) -> Option<&(dyn RefArg + 'static)> where Self: 'static { |
| 520 | self.data.get(index).map(|x| x as &dyn RefArg) |
| 521 | } |
| 522 | #[inline ] |
| 523 | fn box_clone(&self) -> Box<dyn RefArg + 'static> { |
| 524 | Box::new(InternalArray { |
| 525 | data: self.data.iter().map(|x| x.box_clone()).collect(), |
| 526 | inner_sig: self.inner_sig.clone(), |
| 527 | }) |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | fn get_dict_refarg_for_value_type<'a, K, KF>( |
| 532 | value_type: ArgType, |
| 533 | i: &mut Iter<'a>, |
| 534 | kf: KF, |
| 535 | ) -> Box<dyn RefArg> |
| 536 | where |
| 537 | K: DictKey + 'static + RefArg + Clone + Eq + Hash, |
| 538 | KF: FnMut(&mut Iter<'a>) -> Option<K>, |
| 539 | { |
| 540 | match value_type { |
| 541 | ArgType::Variant => { |
| 542 | get_dict_refarg::<K, Variant<Box<dyn RefArg>>, KF, _>(i, kf, Variant::new_refarg) |
| 543 | } |
| 544 | // Most of the following could also use get_dict_refarg to convert to a typed HashMap, but |
| 545 | // doing so results in a large binary size increase due to all the generic instances being |
| 546 | // instantiated. |
| 547 | ArgType::Byte |
| 548 | | ArgType::Int16 |
| 549 | | ArgType::UInt16 |
| 550 | | ArgType::Int32 |
| 551 | | ArgType::UInt32 |
| 552 | | ArgType::Int64 |
| 553 | | ArgType::UInt64 |
| 554 | | ArgType::Double |
| 555 | | ArgType::String |
| 556 | | ArgType::ObjectPath |
| 557 | | ArgType::Signature |
| 558 | | ArgType::Boolean |
| 559 | | ArgType::UnixFd |
| 560 | | ArgType::Array |
| 561 | | ArgType::Struct => get_internal_dict_refarg::<K, KF>(i, kf), |
| 562 | ArgType::DictEntry => panic!("Can't have DictEntry as value for dictionary" ), |
| 563 | ArgType::Invalid => panic!("Array with invalid dictvalue" ), |
| 564 | } |
| 565 | } |
| 566 | |
| 567 | pub fn get_array_refarg(i: &mut Iter) -> Box<dyn RefArg> { |
| 568 | debug_assert!(i.arg_type() == ArgType::Array); |
| 569 | let etype = ArgType::from_i32(unsafe { ffi::dbus_message_iter_get_element_type(&mut i.0) } as i32).unwrap(); |
| 570 | |
| 571 | let x = match etype { |
| 572 | ArgType::Byte => get_fixed_array_refarg::<u8>(i), |
| 573 | ArgType::Int16 => get_fixed_array_refarg::<i16>(i), |
| 574 | ArgType::UInt16 => get_fixed_array_refarg::<u16>(i), |
| 575 | ArgType::Int32 => get_fixed_array_refarg::<i32>(i), |
| 576 | ArgType::UInt32 => get_fixed_array_refarg::<u32>(i), |
| 577 | ArgType::Int64 => get_fixed_array_refarg::<i64>(i), |
| 578 | ArgType::UInt64 => get_fixed_array_refarg::<u64>(i), |
| 579 | ArgType::Double => get_fixed_array_refarg::<f64>(i), |
| 580 | ArgType::String => get_var_array_refarg::<String, _>(i, |si| si.get()), |
| 581 | ArgType::ObjectPath => get_var_array_refarg::<Path<'static>, _>(i, |si| si.get::<Path>().map(|s| s.into_static())), |
| 582 | ArgType::Signature => get_var_array_refarg::<Signature<'static>, _>(i, |si| si.get::<Signature>().map(|s| s.into_static())), |
| 583 | ArgType::Variant => get_var_array_refarg::<Variant<Box<dyn RefArg>>, _>(i, |si| Variant::new_refarg(si)), |
| 584 | ArgType::Boolean => get_var_array_refarg::<bool, _>(i, |si| si.get()), |
| 585 | ArgType::Invalid => panic!("Array with Invalid ArgType" ), |
| 586 | ArgType::Array => get_internal_array(i), |
| 587 | ArgType::DictEntry => { |
| 588 | let key = ArgType::from_i32(i.signature().as_bytes()[2] as i32).unwrap(); // The third character, after "a{", is our key. |
| 589 | let value = ArgType::from_i32(i.signature().as_bytes()[3] as i32).unwrap(); // The fourth character, after "a{", is our value. |
| 590 | match key { |
| 591 | ArgType::Byte => get_dict_refarg_for_value_type::<u8, _>(value, i, Iter::get), |
| 592 | ArgType::Int16 => get_dict_refarg_for_value_type::<i16, _>(value, i, Iter::get), |
| 593 | ArgType::UInt16 => get_dict_refarg_for_value_type::<u16, _>(value, i, Iter::get), |
| 594 | ArgType::Int32 => get_dict_refarg_for_value_type::<i32, _>(value, i, Iter::get), |
| 595 | ArgType::UInt32 => get_dict_refarg_for_value_type::<u32, _>(value, i, Iter::get), |
| 596 | ArgType::Int64 => get_dict_refarg_for_value_type::<i64, _>(value, i, Iter::get), |
| 597 | ArgType::UInt64 => get_dict_refarg_for_value_type::<u64, _>(value, i, Iter::get), |
| 598 | ArgType::Double => get_internal_dict_refarg::<f64, _>(i, Iter::get), |
| 599 | ArgType::Boolean => get_dict_refarg_for_value_type::<bool, _>(value, i, Iter::get), |
| 600 | // ArgType::UnixFd => get_dict_refarg::<OwnedFd, _>(i), |
| 601 | ArgType::String => get_dict_refarg_for_value_type::<String, _>(value, i, Iter::get), |
| 602 | ArgType::ObjectPath => { |
| 603 | get_dict_refarg_for_value_type::<Path<'static>, _>(value, i, |si| { |
| 604 | si.get::<Path>().map(|s| s.into_static()) |
| 605 | }) |
| 606 | } |
| 607 | ArgType::Signature => { |
| 608 | get_dict_refarg_for_value_type::<Signature<'static>, _>(value, i, |si| { |
| 609 | si.get::<Signature>().map(|s| s.into_static()) |
| 610 | }) |
| 611 | } |
| 612 | _ => panic!("Array with invalid dictkey ({:?})" , key), |
| 613 | } |
| 614 | } |
| 615 | ArgType::UnixFd => get_var_array_refarg::<std::fs::File, _>(i, |si| si.get()), |
| 616 | ArgType::Struct => get_internal_array(i), |
| 617 | }; |
| 618 | |
| 619 | debug_assert_eq!(i.signature(), x.signature()); |
| 620 | x |
| 621 | } |
| 622 | |