diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/dbus/src/arg | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/dbus/src/arg')
-rw-r--r-- | third_party/rust/dbus/src/arg/array_impl.rs | 483 | ||||
-rw-r--r-- | third_party/rust/dbus/src/arg/basic_impl.rs | 308 | ||||
-rw-r--r-- | third_party/rust/dbus/src/arg/mod.rs | 440 | ||||
-rw-r--r-- | third_party/rust/dbus/src/arg/msgarg.rs | 426 | ||||
-rw-r--r-- | third_party/rust/dbus/src/arg/variantstruct_impl.rs | 242 |
5 files changed, 1899 insertions, 0 deletions
diff --git a/third_party/rust/dbus/src/arg/array_impl.rs b/third_party/rust/dbus/src/arg/array_impl.rs new file mode 100644 index 0000000000..8bccf347a4 --- /dev/null +++ b/third_party/rust/dbus/src/arg/array_impl.rs @@ -0,0 +1,483 @@ +use super::*; +use {Signature, Path, Message, ffi, OwnedFd}; +use std::marker::PhantomData; +use std::{ptr, mem, any, fmt}; +use super::check; +use std::ffi::{CString}; +use std::os::raw::{c_void, c_int}; +use std::collections::HashMap; +use std::hash::Hash; + +// Map DBus-Type -> Alignment. Copied from _dbus_marshal_write_fixed_multi in +// http://dbus.freedesktop.org/doc/api/html/dbus-marshal-basic_8c_source.html#l01020 +// Note that Rust booleans are one byte, dbus booleans are four bytes! +const FIXED_ARRAY_ALIGNMENTS: [(ArgType, usize); 9] = [ + (ArgType::Byte, 1), + (ArgType::Int16, 2), + (ArgType::UInt16, 2), + (ArgType::UInt32, 4), + (ArgType::Int32, 4), + (ArgType::Boolean, 4), + (ArgType::Int64, 8), + (ArgType::UInt64, 8), + (ArgType::Double, 8) +]; + +/// Represents a D-Bus array. +impl<'a, T: Arg> Arg for &'a [T] { + const ARG_TYPE: ArgType = ArgType::Array; + fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) } +} + +fn array_append<T: Arg, F: FnMut(&T, &mut IterAppend)>(z: &[T], i: &mut IterAppend, mut f: F) { + let zptr = z.as_ptr(); + let zlen = z.len() as i32; + + // Can we do append_fixed_array? + let a = (T::ARG_TYPE, mem::size_of::<T>()); + let can_fixed_array = (zlen > 1) && (z.len() == zlen as usize) && FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == a); + + i.append_container(ArgType::Array, Some(T::signature().as_cstr()), |s| + if can_fixed_array { unsafe { check("dbus_message_iter_append_fixed_array", + ffi::dbus_message_iter_append_fixed_array(&mut s.0, a.0 as c_int, &zptr as *const _ as *const c_void, zlen)) }} + else { for arg in z { f(arg, s); }} + ); +} + +/// Appends a D-Bus array. Note: In case you have a large array of a type that implements FixedArray, +/// using this method will be more efficient than using an Array. +impl<'a, T: Arg + Append + Clone> Append for &'a [T] { + fn append(self, i: &mut IterAppend) { + array_append(self, i, |arg, s| arg.clone().append(s)); + } +} + +impl<'a, T: Arg + RefArg> RefArg for &'a [T] { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) } + fn append(&self, i: &mut IterAppend) { + array_append(self, i, |arg, s| (arg as &RefArg).append(s)); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalArray { + inner_sig: <T as Arg>::signature(), + data: self.iter().map(|x| x.box_clone()).collect(), + }) + } +} + +impl<T: Arg + RefArg> RefArg for Vec<T> { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) } + fn append(&self, i: &mut IterAppend) { + array_append(&self, i, |arg, s| (arg as &RefArg).append(s)); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { + Some(Box::new(self.iter().map(|b| b as &RefArg))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() } +} + + +impl<'a, T: FixedArray> Get<'a> for &'a [T] { + fn get(i: &mut Iter<'a>) -> Option<&'a [T]> { + debug_assert!(FIXED_ARRAY_ALIGNMENTS.iter().any(|&v| v == (T::ARG_TYPE, mem::size_of::<T>()))); + i.recurse(Self::ARG_TYPE).and_then(|mut si| unsafe { + let etype = ffi::dbus_message_iter_get_element_type(&mut i.0); + + if etype != T::ARG_TYPE as c_int { return None }; + + let mut v = ptr::null_mut(); + let mut i = 0; + ffi::dbus_message_iter_get_fixed_array(&mut si.0, &mut v as *mut _ as *mut c_void, &mut i); + if v == ptr::null_mut() { + assert_eq!(i, 0); + Some(&[][..]) + } else { + Some(::std::slice::from_raw_parts(v, i as usize)) + } + }) + } +} + + +#[derive(Copy, Clone, Debug)] +/// Append a D-Bus dict type (i e, an array of dict entries). +/// +/// See the argument guide and module level documentation for details and alternatives. +pub struct Dict<'a, K: DictKey, V: Arg, I>(I, PhantomData<(&'a Message, *const K, *const V)>); + +impl<'a, K: DictKey, V: Arg, I> Dict<'a, K, V, I> { + fn entry_sig() -> String { format!("{{{}{}}}", K::signature(), V::signature()) } +} + +impl<'a, K: 'a + DictKey, V: 'a + Append + Arg, I: Iterator<Item=(K, V)>> Dict<'a, K, V, I> { + /// Creates a new Dict from an iterator. The iterator is consumed when appended. + pub fn new<J: IntoIterator<IntoIter=I, Item=(K, V)>>(j: J) -> Dict<'a, K, V, I> { Dict(j.into_iter(), PhantomData) } +} + +impl<'a, K: DictKey, V: Arg, I> Arg for Dict<'a, K, V, I> { + const ARG_TYPE: ArgType = ArgType::Array; + fn signature() -> Signature<'static> { + Signature::from(format!("a{}", Self::entry_sig())) } +} + +impl<'a, K: 'a + DictKey + Append, V: 'a + Append + Arg, I: Iterator<Item=(K, V)>> Append for Dict<'a, K, V, I> { + fn append(self, i: &mut IterAppend) { + let z = self.0; + i.append_container(Self::ARG_TYPE, Some(&CString::new(Self::entry_sig()).unwrap()), |s| for (k, v) in z { + s.append_container(ArgType::DictEntry, None, |ss| { + k.append(ss); + v.append(ss); + }) + }); + } +} + + +impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Get<'a> for Dict<'a, K, V, Iter<'a>> { + fn get(i: &mut Iter<'a>) -> Option<Self> { + i.recurse(Self::ARG_TYPE).map(|si| Dict(si, PhantomData)) + // TODO: Verify full element signature? + } +} + +impl<'a, K: DictKey + Get<'a>, V: Arg + Get<'a>> Iterator for Dict<'a, K, V, Iter<'a>> { + type Item = (K, V); + fn next(&mut self) -> Option<(K, V)> { + let i = self.0.recurse(ArgType::DictEntry).and_then(|mut si| { + let k = si.get(); + if k.is_none() { return None }; + assert!(si.next()); + let v = si.get(); + if v.is_none() { return None }; + Some((k.unwrap(), v.unwrap())) + }); + self.0.next(); + i + } +} + +impl<K: DictKey, V: Arg> Arg for HashMap<K, V> { + const ARG_TYPE: ArgType = ArgType::Array; + fn signature() -> Signature<'static> { + Signature::from(format!("a{{{}{}}}", K::signature(), V::signature())) } +} + +impl<K: DictKey + Append + Eq + Hash, V: Arg + Append> Append for HashMap<K, V> { + fn append(self, i: &mut IterAppend) { + Dict::new(self.into_iter()).append(i); + } +} + +impl<'a, K: DictKey + Get<'a> + Eq + Hash, V: Arg + Get<'a>> Get<'a> for HashMap<K, V> { + fn get(i: &mut Iter<'a>) -> Option<Self> { + // TODO: Full element signature is not verified. + Dict::get(i).map(|d| d.into_iter().collect()) + } +} + +impl<K: DictKey + RefArg + Eq + Hash, V: RefArg + Arg> RefArg for HashMap<K, V> { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { format!("a{{{}{}}}", <K as Arg>::signature(), <V as Arg>::signature()).into() } + fn append(&self, i: &mut IterAppend) { + let sig = CString::new(format!("{{{}{}}}", <K as Arg>::signature(), <V as Arg>::signature())).unwrap(); + i.append_container(ArgType::Array, Some(&sig), |s| for (k, v) in self { + s.append_container(ArgType::DictEntry, None, |ss| { + k.append(ss); + v.append(ss); + }) + }); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { + Some(Box::new(self.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter()))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalDict { + outer_sig: self.signature(), + data: self.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(), + }) + } +} + +impl<T: Arg> Arg for Vec<T> { + const ARG_TYPE: ArgType = ArgType::Array; + fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) } +} + +impl<T: Arg + Append> Append for Vec<T> { + fn append(self, i: &mut IterAppend) { + Array::new(self).append(i); + } +} + +impl<'a, T: Arg + Get<'a>> Get<'a> for Vec<T> { + fn get(i: &mut Iter<'a>) -> Option<Self> { + <Array<T, Iter<'a>>>::get(i).map(|a| a.collect()) + } +} + + +#[derive(Copy, Clone, Debug)] +/// Represents a D-Bus Array. Maximum flexibility (wraps an iterator of items to append). +/// +/// See the argument guide and module level documentation for details and alternatives. +pub struct Array<'a, T, I>(I, PhantomData<(*const T, &'a Message)>); + +impl<'a, T: 'a, I: Iterator<Item=T>> Array<'a, T, I> { + /// Creates a new Array from an iterator. The iterator is consumed when appending. + pub fn new<J: IntoIterator<IntoIter=I, Item=T>>(j: J) -> Array<'a, T, I> { Array(j.into_iter(), PhantomData) } +} + +impl<'a, T: Arg, I> Arg for Array<'a, T, I> { + const ARG_TYPE: ArgType = ArgType::Array; + fn signature() -> Signature<'static> { Signature::from(format!("a{}", T::signature())) } +} + +impl<'a, T: 'a + Arg + Append, I: Iterator<Item=T>> Append for Array<'a, T, I> { + fn append(self, i: &mut IterAppend) { + let z = self.0; + i.append_container(ArgType::Array, Some(T::signature().as_cstr()), |s| for arg in z { arg.append(s) }); + } +} + +impl<'a, T: Arg + Get<'a>> Get<'a> for Array<'a, T, Iter<'a>> { + fn get(i: &mut Iter<'a>) -> Option<Array<'a, T, Iter<'a>>> { + i.recurse(Self::ARG_TYPE).map(|si| Array(si, PhantomData)) + // TODO: Verify full element signature? + } +} + +impl<'a, T: Get<'a>> Iterator for Array<'a, T, Iter<'a>> { + type Item = T; + fn next(&mut self) -> Option<T> { + let i = self.0.get(); + self.0.next(); + i + } +} + +// Due to the strong typing here; RefArg is implemented only for T's that are both Arg and RefArg. +// We need Arg for this to work for empty arrays (we can't get signature from first element if there is no elements). +// We need RefArg for non-consuming append. +impl<'a, T: 'a + Arg + fmt::Debug + RefArg, I: fmt::Debug + Clone + Iterator<Item=&'a T>> RefArg for Array<'static, T, I> { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", <T as Arg>::signature())) } + fn append(&self, i: &mut IterAppend) { + let z = self.0.clone(); + i.append_container(ArgType::Array, Some(<T as Arg>::signature().as_cstr()), |s| + for arg in z { (arg as &RefArg).append(s) } + ); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalArray { + inner_sig: <T as Arg>::signature(), + data: self.0.clone().map(|x| x.box_clone()).collect(), + }) + } +} + +fn get_fixed_array_refarg<'a, T: FixedArray + Clone + RefArg>(i: &mut Iter<'a>) -> Box<RefArg> { + let s = <&[T]>::get(i).unwrap(); + Box::new(s.to_vec()) +} + +fn get_var_array_refarg<'a, T: 'static + RefArg + Arg, F: FnMut(&mut Iter<'a>) -> Option<T>> + (i: &mut Iter<'a>, mut f: F) -> Box<RefArg> { + let mut v: Vec<T> = vec!(); // dbus_message_iter_get_element_count might be O(n), better not use it + let mut si = i.recurse(ArgType::Array).unwrap(); + while let Some(q) = f(&mut si) { v.push(q); si.next(); } + Box::new(v) +} + + +#[derive(Debug)] +struct InternalDict<K> { + data: Vec<(K, Box<RefArg>)>, + outer_sig: Signature<'static>, +} + +fn get_dict_refarg<'a, K, F: FnMut(&mut Iter<'a>) -> Option<K>>(i: &mut Iter<'a>, mut f: F) -> Box<RefArg> + where K: DictKey + 'static + RefArg + Clone + { + let mut data = vec!(); + let outer_sig = i.signature(); + let mut si = i.recurse(ArgType::Array).unwrap(); + while let Some(mut d) = si.recurse(ArgType::DictEntry) { + let k = f(&mut d).unwrap(); + d.next(); + data.push((k, d.get_refarg().unwrap())); + si.next(); + } + Box::new(InternalDict { data, outer_sig }) +} + +// This only happens from box_clone +impl RefArg for InternalDict<Box<RefArg>> { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { self.outer_sig.clone() } + fn append(&self, i: &mut IterAppend) { + let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..]; + let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap(); + i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data { + s.append_container(ArgType::DictEntry, None, |ss| { + k.append(ss); + v.append(ss); + }) + }); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { + Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter()))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalDict { + data: self.data.iter().map(|(k, v)| (k.box_clone(), v.box_clone())).collect(), + outer_sig: self.outer_sig.clone(), + }) + } +} + + +impl<K: DictKey + RefArg + Clone + 'static> RefArg for InternalDict<K> { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { self.outer_sig.clone() } + fn append(&self, i: &mut IterAppend) { + let inner_sig = &self.outer_sig.as_cstr().to_bytes_with_nul()[1..]; + let inner_sig = CStr::from_bytes_with_nul(inner_sig).unwrap(); + i.append_container(ArgType::Array, Some(inner_sig), |s| for (k, v) in &self.data { + s.append_container(ArgType::DictEntry, None, |ss| { + k.append(ss); + v.append(ss); + }) + }); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { + Some(Box::new(self.data.iter().flat_map(|(k, v)| vec![k as &RefArg, v as &RefArg].into_iter()))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalDict { + data: self.data.iter().map(|(k, v)| (k.clone(), v.box_clone())).collect(), + outer_sig: self.outer_sig.clone(), + }) + } +} + + +// Fallback for Arrays of Arrays and Arrays of Structs. +// We store the signature manually here and promise that it is correct for all elements +// has that signature. +#[derive(Debug)] +struct InternalArray { + data: Vec<Box<RefArg>>, + inner_sig: Signature<'static>, +} + +fn get_internal_array<'a>(i: &mut Iter<'a>) -> Box<RefArg> { + let mut si = i.recurse(ArgType::Array).unwrap(); + let inner_sig = si.signature(); + let data = si.collect::<Vec<_>>(); + Box::new(InternalArray { data, inner_sig }) +} + +impl RefArg for InternalArray { + fn arg_type(&self) -> ArgType { ArgType::Array } + fn signature(&self) -> Signature<'static> { Signature::from(format!("a{}", self.inner_sig)) } + fn append(&self, i: &mut IterAppend) { + i.append_container(ArgType::Array, Some(self.inner_sig.as_cstr()), |s| + for arg in &self.data { (arg as &RefArg).append(s) } + ); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { + Some(Box::new(self.data.iter().map(|b| b as &RefArg))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + Box::new(InternalArray { + data: self.data.iter().map(|x| x.box_clone()).collect(), + inner_sig: self.inner_sig.clone(), + }) + } +} + +pub fn get_array_refarg<'a>(i: &mut Iter<'a>) -> Box<RefArg> { + debug_assert!(i.arg_type() == ArgType::Array); + let etype = ArgType::from_i32(unsafe { ffi::dbus_message_iter_get_element_type(&mut i.0) } as i32).unwrap(); + + let x = match etype { + ArgType::Byte => get_fixed_array_refarg::<u8>(i), + ArgType::Int16 => get_fixed_array_refarg::<i16>(i), + ArgType::UInt16 => get_fixed_array_refarg::<u16>(i), + ArgType::Int32 => get_fixed_array_refarg::<i32>(i), + ArgType::UInt32 => get_fixed_array_refarg::<u32>(i), + ArgType::Int64 => get_fixed_array_refarg::<i64>(i), + ArgType::UInt64 => get_fixed_array_refarg::<u64>(i), + ArgType::Double => get_fixed_array_refarg::<f64>(i), + ArgType::String => get_var_array_refarg::<String, _>(i, |si| si.get()), + ArgType::ObjectPath => get_var_array_refarg::<Path<'static>, _>(i, |si| si.get::<Path>().map(|s| s.into_static())), + ArgType::Signature => get_var_array_refarg::<Signature<'static>, _>(i, |si| si.get::<Signature>().map(|s| s.into_static())), + ArgType::Variant => get_var_array_refarg::<Variant<Box<RefArg>>, _>(i, |si| Variant::new_refarg(si)), + ArgType::Boolean => get_var_array_refarg::<bool, _>(i, |si| si.get()), + ArgType::Invalid => panic!("Array with Invalid ArgType"), + ArgType::Array => get_internal_array(i), + ArgType::DictEntry => { + let key = ArgType::from_i32(i.signature().as_bytes()[2] as i32).unwrap(); // The third character, after "a{", is our key. + match key { + ArgType::Byte => get_dict_refarg::<u8, _>(i, |si| si.get()), + ArgType::Int16 => get_dict_refarg::<i16, _>(i, |si| si.get()), + ArgType::UInt16 => get_dict_refarg::<u16, _>(i, |si| si.get()), + ArgType::Int32 => get_dict_refarg::<i32, _>(i, |si| si.get()), + ArgType::UInt32 => get_dict_refarg::<u32, _>(i, |si| si.get()), + ArgType::Int64 => get_dict_refarg::<i64, _>(i, |si| si.get()), + ArgType::UInt64 => get_dict_refarg::<u64, _>(i, |si| si.get()), + ArgType::Double => get_dict_refarg::<f64, _>(i, |si| si.get()), + ArgType::Boolean => get_dict_refarg::<bool, _>(i, |si| si.get()), + // ArgType::UnixFd => get_dict_refarg::<OwnedFd, _>(i, |si| si.get()), + ArgType::String => get_dict_refarg::<String, _>(i, |si| si.get()), + ArgType::ObjectPath => get_dict_refarg::<Path<'static>, _>(i, |si| si.get::<Path>().map(|s| s.into_static())), + ArgType::Signature => get_dict_refarg::<Signature<'static>, _>(i, |si| si.get::<Signature>().map(|s| s.into_static())), + _ => panic!("Array with invalid dictkey ({:?})", key), + } + } + ArgType::UnixFd => get_var_array_refarg::<OwnedFd, _>(i, |si| si.get()), + ArgType::Struct => get_internal_array(i), + }; + + debug_assert_eq!(i.signature(), x.signature()); + x +} + + diff --git a/third_party/rust/dbus/src/arg/basic_impl.rs b/third_party/rust/dbus/src/arg/basic_impl.rs new file mode 100644 index 0000000000..66d2a0ee74 --- /dev/null +++ b/third_party/rust/dbus/src/arg/basic_impl.rs @@ -0,0 +1,308 @@ +use ffi; +use super::*; +use super::check; +use {Signature, Path, OwnedFd}; +use std::{ptr, any, mem}; +use std::ffi::CStr; +use std::os::raw::{c_void, c_char, c_int}; + + +fn arg_append_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: T) { + let p = &v as *const _ as *const c_void; + unsafe { + check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, p)); + }; +} + +fn arg_get_basic<T>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<T> { + unsafe { + let mut c: T = mem::zeroed(); + if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None }; + ffi::dbus_message_iter_get_basic(i, &mut c as *mut _ as *mut c_void); + Some(c) + } +} + +fn arg_append_f64(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: f64) { + let p = &v as *const _ as *const c_void; + unsafe { + check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, p)); + }; +} + +fn arg_get_f64(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<f64> { + let mut c = 0f64; + unsafe { + if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None }; + ffi::dbus_message_iter_get_basic(i, &mut c as *mut _ as *mut c_void); + } + Some(c) +} + +fn arg_append_str(i: *mut ffi::DBusMessageIter, arg_type: ArgType, v: &CStr) { + let p = v.as_ptr(); + let q = &p as *const _ as *const c_void; + unsafe { + check("dbus_message_iter_append_basic", ffi::dbus_message_iter_append_basic(i, arg_type as c_int, q)); + }; +} + +unsafe fn arg_get_str<'a>(i: *mut ffi::DBusMessageIter, arg_type: ArgType) -> Option<&'a CStr> { + if ffi::dbus_message_iter_get_arg_type(i) != arg_type as c_int { return None }; + let mut p = ptr::null_mut(); + ffi::dbus_message_iter_get_basic(i, &mut p as *mut _ as *mut c_void); + Some(CStr::from_ptr(p as *const c_char)) +} + + + + +// Implementation for basic types. + +macro_rules! integer_impl { + ($t: ident, $s: ident, $f: expr, $i: ident, $ii: expr, $u: ident, $uu: expr, $fff: ident, $ff: expr) => { + +impl Arg for $t { + const ARG_TYPE: ArgType = ArgType::$s; + #[inline] + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } +} + +impl Append for $t { + fn append(self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, self) } +} + +impl<'a> Get<'a> for $t { + fn get(i: &mut Iter) -> Option<Self> { arg_get_basic(&mut i.0, ArgType::$s) } +} + +impl RefArg for $t { + #[inline] + fn arg_type(&self) -> ArgType { ArgType::$s } + #[inline] + fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } + #[inline] + fn append(&self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::$s, *self) } + #[inline] + fn as_any(&self) -> &any::Any { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any { self } + #[inline] + fn as_i64(&self) -> Option<i64> { let $i = *self; $ii } + #[inline] + fn as_u64(&self) -> Option<u64> { let $u = *self; $uu } + #[inline] + fn as_f64(&self) -> Option<f64> { let $fff = *self; $ff } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) } +} + +impl DictKey for $t {} +unsafe impl FixedArray for $t {} + +}} // End of macro_rules + +integer_impl!(u8, Byte, b"y\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); +integer_impl!(i16, Int16, b"n\0", i, Some(i as i64), _u, None, f, Some(f as f64)); +integer_impl!(u16, UInt16, b"q\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); +integer_impl!(i32, Int32, b"i\0", i, Some(i as i64), _u, None, f, Some(f as f64)); +integer_impl!(u32, UInt32, b"u\0", i, Some(i as i64), u, Some(u as u64), f, Some(f as f64)); +integer_impl!(i64, Int64, b"x\0", i, Some(i), _u, None, _f, None); +integer_impl!(u64, UInt64, b"t\0", _i, None, u, Some(u as u64), _f, None); + + +macro_rules! refarg_impl { + ($t: ty, $i: ident, $ii: expr, $ss: expr, $uu: expr, $ff: expr) => { + +impl RefArg for $t { + #[inline] + fn arg_type(&self) -> ArgType { <$t as Arg>::ARG_TYPE } + #[inline] + fn signature(&self) -> Signature<'static> { <$t as Arg>::signature() } + #[inline] + fn append(&self, i: &mut IterAppend) { <$t as Append>::append(self.clone(), i) } + #[inline] + fn as_any(&self) -> &any::Any { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any { self } + #[inline] + fn as_i64(&self) -> Option<i64> { let $i = self; $ii } + #[inline] + fn as_u64(&self) -> Option<u64> { let $i = self; $uu } + #[inline] + fn as_f64(&self) -> Option<f64> { let $i = self; $ff } + #[inline] + fn as_str(&self) -> Option<&str> { let $i = self; $ss } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) } +} + + } +} + + +impl Arg for bool { + const ARG_TYPE: ArgType = ArgType::Boolean; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"b\0") } } +} +impl Append for bool { + fn append(self, i: &mut IterAppend) { arg_append_basic(&mut i.0, ArgType::Boolean, if self {1} else {0}) } +} +impl DictKey for bool {} +impl<'a> Get<'a> for bool { + fn get(i: &mut Iter) -> Option<Self> { arg_get_basic::<u32>(&mut i.0, ArgType::Boolean).map(|q| q != 0) } +} + +refarg_impl!(bool, _i, Some(if *_i { 1 } else { 0 }), None, Some(if *_i { 1 as u64 } else { 0 as u64 }), Some(if *_i { 1 as f64 } else { 0 as f64 })); + +impl Arg for f64 { + const ARG_TYPE: ArgType = ArgType::Double; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"d\0") } } +} +impl Append for f64 { + fn append(self, i: &mut IterAppend) { arg_append_f64(&mut i.0, ArgType::Double, self) } +} +impl DictKey for f64 {} +impl<'a> Get<'a> for f64 { + fn get(i: &mut Iter) -> Option<Self> { arg_get_f64(&mut i.0, ArgType::Double) } +} +unsafe impl FixedArray for f64 {} + +refarg_impl!(f64, _i, None, None, None, Some(*_i)); + +/// Represents a D-Bus string. +impl<'a> Arg for &'a str { + const ARG_TYPE: ArgType = ArgType::String; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } } +} + +impl<'a> Append for &'a str { + fn append(self, i: &mut IterAppend) { + use std::borrow::Cow; + let b: &[u8] = self.as_bytes(); + let v: Cow<[u8]> = if b.len() > 0 && b[b.len()-1] == 0 { Cow::Borrowed(b) } + else { + let mut bb: Vec<u8> = b.into(); + bb.push(0); + Cow::Owned(bb) + }; + let z = unsafe { CStr::from_ptr(v.as_ptr() as *const c_char) }; + arg_append_str(&mut i.0, ArgType::String, &z) + } +} +impl<'a> DictKey for &'a str {} +impl<'a> Get<'a> for &'a str { + fn get(i: &mut Iter<'a>) -> Option<&'a str> { unsafe { arg_get_str(&mut i.0, ArgType::String) } + .and_then(|s| s.to_str().ok()) } +} + +impl<'a> Arg for String { + const ARG_TYPE: ArgType = ArgType::String; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } } +} +impl<'a> Append for String { + fn append(mut self, i: &mut IterAppend) { + self.push_str("\0"); + let s: &str = &self; + s.append(i) + } +} +impl<'a> DictKey for String {} +impl<'a> Get<'a> for String { + fn get(i: &mut Iter<'a>) -> Option<String> { <&str>::get(i).map(|s| String::from(s)) } +} + +refarg_impl!(String, _i, None, Some(&_i), None, None); + +/// Represents a D-Bus string. +impl<'a> Arg for &'a CStr { + const ARG_TYPE: ArgType = ArgType::String; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"s\0") } } +} + +/* +/// Note: Will give D-Bus errors in case the CStr is not valid UTF-8. +impl<'a> Append for &'a CStr { + fn append(self, i: &mut IterAppend) { + arg_append_str(&mut i.0, Self::arg_type(), &self) + } +} +*/ + +impl<'a> DictKey for &'a CStr {} +impl<'a> Get<'a> for &'a CStr { + fn get(i: &mut Iter<'a>) -> Option<&'a CStr> { unsafe { arg_get_str(&mut i.0, Self::ARG_TYPE) }} +} + +impl Arg for OwnedFd { + const ARG_TYPE: ArgType = ArgType::UnixFd; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"h\0") } } +} +impl Append for OwnedFd { + fn append(self, i: &mut IterAppend) { + use std::os::unix::io::AsRawFd; + arg_append_basic(&mut i.0, ArgType::UnixFd, self.as_raw_fd()) + } +} +impl DictKey for OwnedFd {} +impl<'a> Get<'a> for OwnedFd { + fn get(i: &mut Iter) -> Option<Self> { + arg_get_basic(&mut i.0, ArgType::UnixFd).map(|q| OwnedFd::new(q)) + } +} + +refarg_impl!(OwnedFd, _i, { use std::os::unix::io::AsRawFd; Some(_i.as_raw_fd() as i64) }, None, None, None); + +macro_rules! string_impl { + ($t: ident, $s: ident, $f: expr) => { + +impl<'a> Arg for $t<'a> { + const ARG_TYPE: ArgType = ArgType::$s; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } +} + +impl RefArg for $t<'static> { + fn arg_type(&self) -> ArgType { ArgType::$s } + fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked($f) } } + fn append(&self, i: &mut IterAppend) { arg_append_str(&mut i.0, ArgType::$s, self.as_cstr()) } + #[inline] + fn as_any(&self) -> &any::Any { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any { self } + #[inline] + fn as_str(&self) -> Option<&str> { Some(self) } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone().into_static()) } +} + +impl<'a> DictKey for $t<'a> {} + +impl<'a> Append for $t<'a> { + fn append(self, i: &mut IterAppend) { + arg_append_str(&mut i.0, ArgType::$s, self.as_cstr()) + } +} + +/* + +Unfortunately, this does not work because it conflicts with getting a $t<'static>. + +impl<'a> Get<'a> for $t<'a> { + fn get(i: &mut Iter<'a>) -> Option<$t<'a>> { unsafe { arg_get_str(&mut i.0, ArgType::$s) } + .map(|s| unsafe { $t::from_slice_unchecked(s.to_bytes_with_nul()) } ) } +} +*/ + +impl<'a> Get<'a> for $t<'static> { + fn get(i: &mut Iter<'a>) -> Option<$t<'static>> { unsafe { + arg_get_str(&mut i.0, ArgType::$s).map(|s| $t::from_slice_unchecked(s.to_bytes_with_nul()).into_static()) + }} +} + + + } +} + +string_impl!(Path, ObjectPath, b"o\0"); +string_impl!(Signature, Signature, b"g\0"); + diff --git a/third_party/rust/dbus/src/arg/mod.rs b/third_party/rust/dbus/src/arg/mod.rs new file mode 100644 index 0000000000..737960b4b8 --- /dev/null +++ b/third_party/rust/dbus/src/arg/mod.rs @@ -0,0 +1,440 @@ +//! Types and traits for easily getting a message's arguments, or appening a message with arguments. +//! +//! Also see the arguments guide (in the examples directory). +//! +//! A message has `read1`, `read2` etc, and `append1`, `append2` etc, which is your +//! starting point into this module's types. +//! +//! **Append a**: +//! +//! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type +//! +//! `&str` - a D-Bus string. D-Bus strings do not allow null characters, so +//! if the string contains null characters, it will be cropped +//! to only include the data before the null character. (Tip: This allows for skipping an +//! allocation by writing a string literal which ends with a null character.) +//! +//! `&[T] where T: Append` - a D-Bus array. Note: can use an efficient fast-path in case of +//! T being an FixedArray type. +//! +//! `Array<T, I> where T: Append, I: Iterator<Item=T>` - a D-Bus array, maximum flexibility. +//! +//! `Variant<T> where T: Append` - a D-Bus variant. +//! +//! `(T1, T2) where T1: Append, T2: Append` - tuples are D-Bus structs. Implemented up to 12. +//! +//! `Dict<K, V, I> where K: Append + DictKey, V: Append, I: Iterator<Item=(&K, &V)>` - A D-Bus dict (array of dict entries). +//! +//! `Path` - a D-Bus object path. +//! +//! `Signature` - a D-Bus signature. +//! +//! `OwnedFd` - shares the file descriptor with the remote side. +//! +//! **Get / read a**: +//! +//! `bool, u8, u16, u32, u64, i16, i32, i64, f64` - the corresponding D-Bus basic type +//! +//! `&str`, `&CStr` - a D-Bus string. D-Bus strings are always UTF-8 and do not contain null characters. +//! +//! `&[T] where T: FixedArray` - a D-Bus array of integers or f64. +//! +//! `Array<T, Iter> where T: Get` - a D-Bus array, maximum flexibility. Implements Iterator so you can easily +//! collect it into, e g, a `Vec`. +//! +//! `Variant<T> where T: Get` - a D-Bus variant. Use this type of Variant if you know the inner type. +//! +//! `Variant<Iter>` - a D-Bus variant. This type of Variant allows you to examine the inner type. +//! +//! `(T1, T2) where T1: Get, T2: Get` - tuples are D-Bus structs. Implemented up to 12. +//! +//! `Dict<K, V, Iter> where K: Get + DictKey, V: Get` - A D-Bus dict (array of dict entries). Implements Iterator so you can easily +//! collect it into, e g, a `HashMap`. +//! +//! `Path` - a D-Bus object path. +//! +//! `Signature` - a D-Bus signature. +//! +//! `OwnedFd` - a file descriptor sent from the remote side. +//! + +mod msgarg; +mod basic_impl; +mod variantstruct_impl; +mod array_impl; + +pub use self::msgarg::{Arg, FixedArray, Get, DictKey, Append, RefArg, AppendAll, ReadAll, cast, cast_mut}; +pub use self::array_impl::{Array, Dict}; +pub use self::variantstruct_impl::Variant; + +use std::{fmt, mem, ptr, error}; +use {ffi, Message, Signature, Path, OwnedFd}; +use std::ffi::{CStr, CString}; +use std::os::raw::{c_void, c_int}; + + +fn check(f: &str, i: u32) { if i == 0 { panic!("D-Bus error: '{}' failed", f) }} + +fn ffi_iter() -> ffi::DBusMessageIter { unsafe { mem::zeroed() }} + +#[derive(Clone, Copy)] +/// Helper struct for appending one or more arguments to a Message. +pub struct IterAppend<'a>(ffi::DBusMessageIter, &'a Message); + +impl<'a> IterAppend<'a> { + /// Creates a new IterAppend struct. + pub fn new(m: &'a mut Message) -> IterAppend<'a> { + let mut i = ffi_iter(); + unsafe { ffi::dbus_message_iter_init_append(m.ptr(), &mut i) }; + IterAppend(i, m) + } + + /// Appends the argument. + pub fn append<T: Append>(&mut self, a: T) { a.append(self) } + + fn append_container<F: FnOnce(&mut IterAppend<'a>)>(&mut self, arg_type: ArgType, sig: Option<&CStr>, f: F) { + let mut s = IterAppend(ffi_iter(), self.1); + let p = sig.map(|s| s.as_ptr()).unwrap_or(ptr::null()); + check("dbus_message_iter_open_container", + unsafe { ffi::dbus_message_iter_open_container(&mut self.0, arg_type as c_int, p, &mut s.0) }); + f(&mut s); + check("dbus_message_iter_close_container", + unsafe { ffi::dbus_message_iter_close_container(&mut self.0, &mut s.0) }); + } + + /// Low-level function to append a variant. + /// + /// Use in case the `Variant` struct is not flexible enough - + /// the easier way is to just call e g "append1" on a message and supply a `Variant` parameter. + /// + /// In order not to get D-Bus errors: during the call to "f" you need to call "append" on + /// the supplied `IterAppend` exactly once, + /// and with a value which has the same signature as inner_sig. + pub fn append_variant<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) { + self.append_container(ArgType::Variant, Some(inner_sig.as_cstr()), f) + } + + /// Low-level function to append an array. + /// + /// Use in case the `Array` struct is not flexible enough - + /// the easier way is to just call e g "append1" on a message and supply an `Array` parameter. + /// + /// In order not to get D-Bus errors: during the call to "f", you should only call "append" on + /// the supplied `IterAppend` with values which has the same signature as inner_sig. + pub fn append_array<F: FnOnce(&mut IterAppend<'a>)>(&mut self, inner_sig: &Signature, f: F) { + self.append_container(ArgType::Array, Some(inner_sig.as_cstr()), f) + } + + /// Low-level function to append a struct. + /// + /// Use in case tuples are not flexible enough - + /// the easier way is to just call e g "append1" on a message and supply a tuple parameter. + pub fn append_struct<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) { + self.append_container(ArgType::Struct, None, f) + } + + /// Low-level function to append a dict entry. + /// + /// Use in case the `Dict` struct is not flexible enough - + /// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter. + /// + /// In order not to get D-Bus errors: during the call to "f", you should call "append" once + /// for the key, then once for the value. You should only call this function for a subiterator + /// you got from calling "append_dict", and signatures need to match what you specified in "append_dict". + pub fn append_dict_entry<F: FnOnce(&mut IterAppend<'a>)>(&mut self, f: F) { + self.append_container(ArgType::DictEntry, None, f) + } + + /// Low-level function to append a dict. + /// + /// Use in case the `Dict` struct is not flexible enough - + /// the easier way is to just call e g "append1" on a message and supply a `Dict` parameter. + /// + /// In order not to get D-Bus errors: during the call to "f", you should only call "append_dict_entry" + /// for the subiterator - do this as many times as the number of dict entries. + pub fn append_dict<F: FnOnce(&mut IterAppend<'a>)>(&mut self, key_sig: &Signature, value_sig: &Signature, f: F) { + let sig = format!("{{{}{}}}", key_sig, value_sig); + self.append_container(Array::<bool,()>::ARG_TYPE, Some(&CString::new(sig).unwrap()), f); + } +} + + + +#[derive(Clone, Copy)] +/// Helper struct for retrieve one or more arguments from a Message. +pub struct Iter<'a>(ffi::DBusMessageIter, &'a Message, u32); + +impl<'a> Iter<'a> { + /// Creates a new struct for iterating over the arguments of a message, starting with the first argument. + pub fn new(m: &'a Message) -> Iter<'a> { + let mut i = ffi_iter(); + unsafe { ffi::dbus_message_iter_init(m.ptr(), &mut i) }; + Iter(i, m, 0) + } + + /// Returns the current argument, if T is the argument type. Otherwise returns None. + pub fn get<T: Get<'a>>(&mut self) -> Option<T> { + T::get(self) + } + + /// Returns the current argument as a trait object (experimental). + /// + /// Note: For the more complex arguments (arrays / dicts / structs, and especially + /// combinations thereof), their internal representations are still a bit in flux. + /// Instead, use as_iter() to read the values of those. + /// + /// The rest are unlikely to change - Variants are `Variant<Box<RefArg>>`, strings are `String`, + /// paths are `Path<'static>`, signatures are `Signature<'static>`, Int32 are `i32s` and so on. + pub fn get_refarg(&mut self) -> Option<Box<RefArg + 'static>> { + Some(match self.arg_type() { + ArgType::Array => array_impl::get_array_refarg(self), + ArgType::Variant => Box::new(Variant::new_refarg(self).unwrap()), + ArgType::Boolean => Box::new(self.get::<bool>().unwrap()), + ArgType::Invalid => return None, + ArgType::String => Box::new(self.get::<String>().unwrap()), + ArgType::DictEntry => unimplemented!(), + ArgType::Byte => Box::new(self.get::<u8>().unwrap()), + ArgType::Int16 => Box::new(self.get::<i16>().unwrap()), + ArgType::UInt16 => Box::new(self.get::<u16>().unwrap()), + ArgType::Int32 => Box::new(self.get::<i32>().unwrap()), + ArgType::UInt32 => Box::new(self.get::<u32>().unwrap()), + ArgType::Int64 => Box::new(self.get::<i64>().unwrap()), + ArgType::UInt64 => Box::new(self.get::<u64>().unwrap()), + ArgType::Double => Box::new(self.get::<f64>().unwrap()), + ArgType::UnixFd => Box::new(self.get::<OwnedFd>().unwrap()), + ArgType::Struct => Box::new(self.recurse(ArgType::Struct).unwrap().collect::<Vec<_>>()), + ArgType::ObjectPath => Box::new(self.get::<Path>().unwrap().into_static()), + ArgType::Signature => Box::new(self.get::<Signature>().unwrap().into_static()), + }) + } + + /// Returns the type signature for the current argument. + pub fn signature(&mut self) -> Signature<'static> { + unsafe { + let c = ffi::dbus_message_iter_get_signature(&mut self.0); + assert!(c != ptr::null_mut()); + let cc = CStr::from_ptr(c); + let r = Signature::new(cc.to_bytes()); + ffi::dbus_free(c as *mut c_void); + r.unwrap() + } + } + + /// The raw arg_type for the current item. + /// + /// Unlike Arg::arg_type, this requires access to self and is not a static method. + /// You can match this against Arg::arg_type for different types to understand what type the current item is. + /// In case you're past the last argument, this function will return 0. + pub fn arg_type(&mut self) -> ArgType { + let s = unsafe { ffi::dbus_message_iter_get_arg_type(&mut self.0) }; + ArgType::from_i32(s as i32).unwrap() + } + + /// Returns false if there are no more items. + pub fn next(&mut self) -> bool { + self.2 += 1; + unsafe { ffi::dbus_message_iter_next(&mut self.0) != 0 } + } + + /// Wrapper around `get` and `next`. Calls `get`, and then `next` if `get` succeeded. + /// + /// Also returns a `Result` rather than an `Option` to give an error if successful. + /// + /// # Example + /// ```ignore + /// struct ServiceBrowserItemNew { + /// interface: i32, + /// protocol: i32, + /// name: String, + /// item_type: String, + /// domain: String, + /// flags: u32, + /// } + /// + /// fn service_browser_item_new_msg(m: &Message) -> Result<ServiceBrowserItemNew, TypeMismatchError> { + /// let mut iter = m.iter_init(); + /// Ok(ServiceBrowserItemNew { + /// interface: iter.read()?, + /// protocol: iter.read()?, + /// name: iter.read()?, + /// item_type: iter.read()?, + /// domain: iter.read()?, + /// flags: iter.read()?, + /// }) + /// } + /// ``` + pub fn read<T: Arg + Get<'a>>(&mut self) -> Result<T, TypeMismatchError> { + let r = try!(self.get().ok_or_else(|| + TypeMismatchError { expected: T::ARG_TYPE, found: self.arg_type(), position: self.2 })); + self.next(); + Ok(r) + } + + /// If the current argument is a container of the specified arg_type, then a new + /// Iter is returned which is for iterating over the contents inside the container. + /// + /// Primarily for internal use (the "get" function is more ergonomic), but could be + /// useful for recursing into containers with unknown types. + pub fn recurse(&mut self, arg_type: ArgType) -> Option<Iter<'a>> { + let containers = [ArgType::Array, ArgType::DictEntry, ArgType::Struct, ArgType::Variant]; + if !containers.iter().any(|&t| t == arg_type) { return None; } + + let mut subiter = ffi_iter(); + unsafe { + if ffi::dbus_message_iter_get_arg_type(&mut self.0) != arg_type as c_int { return None }; + ffi::dbus_message_iter_recurse(&mut self.0, &mut subiter) + } + Some(Iter(subiter, self.1, 0)) + } +} + +impl<'a> fmt::Debug for Iter<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let mut z = self.clone(); + let mut t = f.debug_tuple("Iter"); + loop { + t.field(&z.arg_type()); + if !z.next() { break } + } + t.finish() + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = Box<RefArg + 'static>; + fn next(&mut self) -> Option<Self::Item> { + let r = self.get_refarg(); + if r.is_some() { self.next(); } + r + } +} + +/// Type of Argument +/// +/// use this to figure out, e g, which type of argument is at the current position of Iter. +#[repr(u8)] +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub enum ArgType { + /// Dicts are Arrays of dict entries, so Dict types will have Array as ArgType. + Array = ffi::DBUS_TYPE_ARRAY as u8, + /// Variant + Variant = ffi::DBUS_TYPE_VARIANT as u8, + /// bool + Boolean = ffi::DBUS_TYPE_BOOLEAN as u8, + /// Invalid arg type - this is also the ArgType returned when there are no more arguments available. + Invalid = ffi::DBUS_TYPE_INVALID as u8, + /// String + String = ffi::DBUS_TYPE_STRING as u8, + /// Dict entry; you'll usually not encounter this one as dicts are arrays of dict entries. + DictEntry = ffi::DBUS_TYPE_DICT_ENTRY as u8, + /// u8 + Byte = ffi::DBUS_TYPE_BYTE as u8, + /// i16 + Int16 = ffi::DBUS_TYPE_INT16 as u8, + /// u16 + UInt16 = ffi::DBUS_TYPE_UINT16 as u8, + /// i32 + Int32 = ffi::DBUS_TYPE_INT32 as u8, + /// u32 + UInt32 = ffi::DBUS_TYPE_UINT32 as u8, + /// i64 + Int64 = ffi::DBUS_TYPE_INT64 as u8, + /// u64 + UInt64 = ffi::DBUS_TYPE_UINT64 as u8, + /// f64 + Double = ffi::DBUS_TYPE_DOUBLE as u8, + /// OwnedFd + UnixFd = ffi::DBUS_TYPE_UNIX_FD as u8, + /// Use tuples or Vec<Box<RefArg>> to read/write structs. + Struct = ffi::DBUS_TYPE_STRUCT as u8, + /// Path + ObjectPath = ffi::DBUS_TYPE_OBJECT_PATH as u8, + /// Signature + Signature = ffi::DBUS_TYPE_SIGNATURE as u8, +} + +const ALL_ARG_TYPES: [(ArgType, &'static str); 18] = + [(ArgType::Variant, "Variant"), + (ArgType::Array, "Array/Dict"), + (ArgType::Struct, "Struct"), + (ArgType::String, "String"), + (ArgType::DictEntry, "Dict entry"), + (ArgType::ObjectPath, "Path"), + (ArgType::Signature, "Signature"), + (ArgType::UnixFd, "OwnedFd"), + (ArgType::Boolean, "bool"), + (ArgType::Byte, "u8"), + (ArgType::Int16, "i16"), + (ArgType::Int32, "i32"), + (ArgType::Int64, "i64"), + (ArgType::UInt16, "u16"), + (ArgType::UInt32, "u32"), + (ArgType::UInt64, "u64"), + (ArgType::Double, "f64"), + (ArgType::Invalid, "nothing")]; + +impl ArgType { + /// A str corresponding to the name of a Rust type. + pub fn as_str(self) -> &'static str { + ALL_ARG_TYPES.iter().skip_while(|a| a.0 != self).next().unwrap().1 + } + + /// Converts an i32 to an ArgType (or an error). + pub fn from_i32(i: i32) -> Result<ArgType, String> { + for &(a, _) in &ALL_ARG_TYPES { + if a as i32 == i { return Ok(a); } + } + Err(format!("Invalid ArgType {} ({})", i, i as u8 as char)) + } +} + + +/// Error struct to indicate a D-Bus argument type mismatch. +/// +/// Might be returned from `iter::read()`. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct TypeMismatchError { + expected: ArgType, + found: ArgType, + position: u32, +} + +impl TypeMismatchError { + /// The ArgType we were trying to read, but failed + pub fn expected_arg_type(&self) -> ArgType { self.expected } + + /// The ArgType we should have been trying to read, if we wanted the read to succeed + pub fn found_arg_type(&self) -> ArgType { self.found } + + /// At what argument was the error found? + /// + /// Returns 0 for first argument, 1 for second argument, etc. + pub fn pos(&self) -> u32 { self.position } +} + +impl error::Error for TypeMismatchError { + fn description(&self) -> &str { "D-Bus argument type mismatch" } + fn cause(&self) -> Option<&error::Error> { None } +} + +impl fmt::Display for TypeMismatchError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{} at position {}: expected {}, found {}", + (self as &error::Error).description(), + self.position, self.expected.as_str(), + if self.expected == self.found { "same but still different somehow" } else { self.found.as_str() } + ) + } +} + + +#[allow(dead_code)] +fn test_compile() { + let mut q = IterAppend::new(unsafe { mem::transmute(0usize) }); + + q.append(5u8); + q.append(Array::new(&[5u8, 6, 7])); + q.append((8u8, &[9u8, 6, 7][..])); + q.append(Variant((6u8, 7u8))); +} + diff --git a/third_party/rust/dbus/src/arg/msgarg.rs b/third_party/rust/dbus/src/arg/msgarg.rs new file mode 100644 index 0000000000..3309c35e65 --- /dev/null +++ b/third_party/rust/dbus/src/arg/msgarg.rs @@ -0,0 +1,426 @@ +#![allow(dead_code)] + +use {Signature, Message, arg::TypeMismatchError}; +use std::{fmt, any}; +use std::sync::Arc; +use std::rc::Rc; + +use super::{Iter, IterAppend, ArgType}; + +/// Types that can represent a D-Bus message argument implement this trait. +/// +/// Types should also implement either Append or Get to be useful. +pub trait Arg { + /// The corresponding D-Bus argument type code. + const ARG_TYPE: ArgType; + /// The corresponding D-Bus argument type code; just returns ARG_TYPE. + /// + /// For backwards compatibility. + #[deprecated(note = "Use associated constant ARG_TYPE instead")] + fn arg_type() -> ArgType { return Self::ARG_TYPE; } + /// The corresponding D-Bus type signature for this type. + fn signature() -> Signature<'static>; +} + +/// Types that can be appended to a message as arguments implement this trait. +pub trait Append: Sized { + /// Performs the append operation. + fn append(self, &mut IterAppend); +} + +/// Helper trait to append many arguments to a message. +pub trait AppendAll: Sized { + /// Performs the append operation. + fn append(self, &mut IterAppend); +} + +/// Types that can be retrieved from a message as arguments implement this trait. +pub trait Get<'a>: Sized { + /// Performs the get operation. + fn get(i: &mut Iter<'a>) -> Option<Self>; +} + +/// Helper trait to read all arguments from a message. +pub trait ReadAll: Sized { + /// Performs the read operation. + fn read(i: &mut Iter) -> Result<Self, TypeMismatchError>; +} + + +/// Object safe version of Arg + Append + Get. +pub trait RefArg: fmt::Debug { + /// The corresponding D-Bus argument type code. + fn arg_type(&self) -> ArgType; + /// The corresponding D-Bus type signature for this type. + fn signature(&self) -> Signature<'static>; + /// Performs the append operation. + fn append(&self, &mut IterAppend); + /// Transforms this argument to Any (which can be downcasted to read the current value). + /// + /// Note: The internal representation of complex types (Array, Dict, Struct) is unstable + /// and as_any should not be relied upon for these types. Use as_iter instead. + fn as_any(&self) -> &any::Any where Self: 'static; + /// Transforms this argument to Any (which can be downcasted to read the current value). + /// + /// Note: The internal representation of complex types (Array, Dict, Struct) is unstable + /// and as_any should not be relied upon for these types. Use as_iter instead. + /// + /// # Panic + /// Will panic if the interior cannot be made mutable, e g, if encapsulated + /// inside a Rc with a reference count > 1. + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static; + /// Try to read the argument as an i64. + /// + /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Int64, UnixFd. + #[inline] + fn as_i64(&self) -> Option<i64> { None } + /// Try to read the argument as an u64. + /// + /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, UInt64. + #[inline] + fn as_u64(&self) -> Option<u64> { None } + /// Try to read the argument as an f64. + /// + /// Works for: Boolean, Byte, Int16, UInt16, Int32, UInt32, Double. + #[inline] + fn as_f64(&self) -> Option<f64> { None } + /// Try to read the argument as a str. + /// + /// Works for: String, ObjectPath, Signature. + #[inline] + fn as_str(&self) -> Option<&str> { None } + /// Try to read the argument as an iterator. + /// + /// Works for: Array/Dict, Struct, Variant. + #[inline] + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { None } + /// Deep clone of the RefArg, causing the result to be 'static. + /// + /// Usable as an escape hatch in case of lifetime problems with RefArg. + /// + /// In case of complex types (Array, Dict, Struct), the clone is not guaranteed + /// to have the same internal representation as the original. + fn box_clone(&self) -> Box<RefArg + 'static> { unimplemented!() /* Needed for backwards comp */ } +} + +impl<'a> Get<'a> for Box<RefArg> { + fn get(i: &mut Iter<'a>) -> Option<Self> { i.get_refarg() } +} + +/// Cast a RefArg as a specific type (shortcut for any + downcast) +#[inline] +pub fn cast<'a, T: 'static>(a: &'a (RefArg + 'static)) -> Option<&'a T> { a.as_any().downcast_ref() } + +/// Cast a RefArg as a specific type (shortcut for any_mut + downcast_mut) +/// +/// # Panic +/// Will panic if the interior cannot be made mutable, e g, if encapsulated +/// inside a Rc with a reference count > 1. +#[inline] +pub fn cast_mut<'a, T: 'static>(a: &'a mut (RefArg + 'static)) -> Option<&'a mut T> { a.as_any_mut().downcast_mut() } + +/// If a type implements this trait, it means the size and alignment is the same +/// as in D-Bus. This means that you can quickly append and get slices of this type. +/// +/// Note: Booleans do not implement this trait because D-Bus booleans are 4 bytes and Rust booleans are 1 byte. +pub unsafe trait FixedArray: Arg + 'static + Clone + Copy {} + +/// Types that can be used as keys in a dict type implement this trait. +pub trait DictKey: Arg {} + + + +/// Simple lift over reference to value - this makes some iterators more ergonomic to use +impl<'a, T: Arg> Arg for &'a T { + const ARG_TYPE: ArgType = T::ARG_TYPE; + fn signature() -> Signature<'static> { T::signature() } +} +impl<'a, T: Append + Clone> Append for &'a T { + fn append(self, i: &mut IterAppend) { self.clone().append(i) } +} +impl<'a, T: DictKey> DictKey for &'a T {} + +impl<'a, T: RefArg + ?Sized> RefArg for &'a T { + #[inline] + fn arg_type(&self) -> ArgType { (&**self).arg_type() } + #[inline] + fn signature(&self) -> Signature<'static> { (&**self).signature() } + #[inline] + fn append(&self, i: &mut IterAppend) { (&**self).append(i) } + #[inline] + fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { unreachable!() } + #[inline] + fn as_i64(&self) -> Option<i64> { (&**self).as_i64() } + #[inline] + fn as_u64(&self) -> Option<u64> { (&**self).as_u64() } + #[inline] + fn as_f64(&self) -> Option<f64> { (&**self).as_f64() } + #[inline] + fn as_str(&self) -> Option<&str> { (&**self).as_str() } + #[inline] + fn as_iter<'b>(&'b self) -> Option<Box<Iterator<Item=&'b RefArg> + 'b>> { (&**self).as_iter() } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() } +} + + + +macro_rules! deref_impl { + ($t: ident, $ss: ident, $make_mut: expr) => { + +impl<T: RefArg + ?Sized> RefArg for $t<T> { + #[inline] + fn arg_type(&self) -> ArgType { (&**self).arg_type() } + #[inline] + fn signature(&self) -> Signature<'static> { (&**self).signature() } + #[inline] + fn append(&self, i: &mut IterAppend) { (&**self).append(i) } + #[inline] + fn as_any(&self) -> &any::Any where T: 'static { (&**self).as_any() } + #[inline] + fn as_any_mut<'a>(&'a mut $ss) -> &'a mut any::Any where T: 'static { $make_mut.as_any_mut() } + #[inline] + fn as_i64(&self) -> Option<i64> { (&**self).as_i64() } + #[inline] + fn as_u64(&self) -> Option<u64> { (&**self).as_u64() } + #[inline] + fn as_f64(&self) -> Option<f64> { (&**self).as_f64() } + #[inline] + fn as_str(&self) -> Option<&str> { (&**self).as_str() } + #[inline] + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { (&**self).as_iter() } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { (&**self).box_clone() } +} +impl<T: DictKey> DictKey for $t<T> {} + +impl<T: Arg> Arg for $t<T> { + const ARG_TYPE: ArgType = T::ARG_TYPE; + fn signature() -> Signature<'static> { T::signature() } +} +impl<'a, T: Get<'a>> Get<'a> for $t<T> { + fn get(i: &mut Iter<'a>) -> Option<Self> { T::get(i).map(|v| $t::new(v)) } +} + + } +} + +impl<T: Append> Append for Box<T> { + fn append(self, i: &mut IterAppend) { let q: T = *self; q.append(i) } +} + +deref_impl!(Box, self, &mut **self ); +deref_impl!(Rc, self, Rc::get_mut(self).unwrap()); +deref_impl!(Arc, self, Arc::get_mut(self).unwrap()); + +/// Internal trait to help generics. Implemented for (), (A1), (A1, A2) and so on (where A1: Arg, A2: Arg etc). +/// +/// You would probably not use this trait directly, instead use generic functions which +/// take ArgBuilder as an argument. It helps reading and appending multiple arguments +/// to/from a message in one go. +pub trait ArgBuilder: Sized { + /// A tuple of &static str. Used for introspection. + type strs; + /// Low-level introspection helper method. + fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(a: Self::strs, f: F); + /// Low-level method to read arguments from a message. + fn read(msg: &Message) -> Result<Self, TypeMismatchError>; + /// Low-level method to append arguments to a message. + fn append(self, msg: &mut Message); +} + +impl ArgBuilder for () { + type strs = (); + fn strs_sig<F: FnMut(&'static str, Signature<'static>)>(_: Self::strs, _: F) {} + fn read(_: &Message) -> Result<Self, TypeMismatchError> { Ok(()) } + fn append(self, _: &mut Message) {} +} + +macro_rules! argbuilder_impl { + ($($n: ident $t: ident $s: ty,)+) => { + +impl<$($t: Arg + Append + for<'z> Get<'z>),*> ArgBuilder for ($($t,)*) { + type strs = ($(&'static $s,)*); + fn strs_sig<Q: FnMut(&'static str, Signature<'static>)>(z: Self::strs, mut q: Q) { + let ( $($n,)*) = z; + $( q($n, $t::signature()); )* + } + + fn read(msg: &Message) -> Result<Self, TypeMismatchError> { + let mut ii = msg.iter_init(); + $( let $n = ii.read()?; )* + Ok(($( $n, )* )) + } + + fn append(self, msg: &mut Message) { + let ( $($n,)*) = self; + let mut ia = IterAppend::new(msg); + $( ia.append($n); )* + } +} + +impl<$($t: Append),*> AppendAll for ($($t,)*) { + fn append(self, ia: &mut IterAppend) { + let ( $($n,)*) = self; + $( ia.append($n); )* + } +} + +impl<$($t: Arg + for<'z> Get<'z>),*> ReadAll for ($($t,)*) { + fn read(ii: &mut Iter) -> Result<Self, TypeMismatchError> { + $( let $n = ii.read()?; )* + Ok(($( $n, )* )) + } +} + + + } +} + +argbuilder_impl!(a A str,); +argbuilder_impl!(a A str, b B str,); +argbuilder_impl!(a A str, b B str, c C str,); +argbuilder_impl!(a A str, b B str, c C str, d D str,); +argbuilder_impl!(a A str, b B str, c C str, d D str, e E str,); +argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str,); +argbuilder_impl!(a A str, b B str, c C str, d D str, e E str, f F str, g G str,); +argbuilder_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,); +argbuilder_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,); +argbuilder_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,); + + + +#[cfg(test)] +mod test { + extern crate tempdir; + + use {Connection, ConnectionItem, Message, BusType, Path, Signature}; + use arg::{Array, Variant, Dict, Iter, ArgType, TypeMismatchError, RefArg, cast}; + + use std::collections::HashMap; + + #[test] + fn refarg() { + let c = Connection::get_private(BusType::Session).unwrap(); + c.register_object_path("/mooh").unwrap(); + let m = Message::new_method_call(&c.unique_name(), "/mooh", "com.example.hello", "Hello").unwrap(); + + let mut vv: Vec<Variant<Box<RefArg>>> = vec!(); + vv.push(Variant(Box::new(5i32))); + vv.push(Variant(Box::new(String::from("Hello world")))); + let m = m.append_ref(&vv); + + let (f1, f2) = (false, 7u64); + let mut v: Vec<&RefArg> = vec!(); + v.push(&f1); + v.push(&f2); + let m = m.append_ref(&v); + let vi32 = vec![7i32, 9i32]; + let vstr: Vec<String> = ["This", "is", "dbus", "rs"].iter().map(|&s| s.into()).collect(); + let m = m.append_ref(&[&vi32 as &RefArg, &vstr as &RefArg]); + let mut map = HashMap::new(); + map.insert(true, String::from("Yes")); + map.insert(false, String::from("No")); + let m = m.append_ref(&[&map as &RefArg, &1.5f64 as &RefArg]); + + c.send(m).unwrap(); + + for n in c.iter(1000) { + if let ConnectionItem::MethodCall(m) = n { + let rv: Vec<Box<RefArg + 'static>> = m.iter_init().collect(); + println!("Receiving {:?}", rv); + let rv0: &Variant<Box<RefArg>> = cast(&rv[0]).unwrap(); + let rv00: &i32 = cast(&rv0.0).unwrap(); + assert_eq!(rv00, &5i32); + assert_eq!(Some(&false), rv[2].as_any().downcast_ref::<bool>()); + assert_eq!(Some(&vi32), rv[4].as_any().downcast_ref::<Vec<i32>>()); + assert_eq!(Some(&vstr), rv[5].as_any().downcast_ref::<Vec<String>>()); + let mut diter = rv[6].as_iter().unwrap(); + { + let mut mmap: HashMap<bool, String> = HashMap::new(); + while let Some(k) = diter.next() { + let x: String = diter.next().unwrap().as_str().unwrap().into(); + mmap.insert(*cast::<bool>(&k.box_clone()).unwrap(), x); + } + assert_eq!(mmap[&true], "Yes"); + } + let mut iter = rv[6].as_iter().unwrap(); + assert!(iter.next().unwrap().as_i64().is_some()); + assert!(iter.next().unwrap().as_str().is_some()); + assert!(iter.next().unwrap().as_str().is_none()); + assert!(iter.next().unwrap().as_i64().is_none()); + assert!(iter.next().is_none()); + assert!(rv[7].as_f64().unwrap() > 1.0); + assert!(rv[7].as_f64().unwrap() < 2.0); + break; + } + } + } + + #[test] + fn message_types() { + let c = Connection::get_private(BusType::Session).unwrap(); + c.register_object_path("/hello").unwrap(); + let m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap(); + let m = m.append1(2000u16); + let m = m.append1(Array::new(&vec![129u8, 5, 254])); + let m = m.append2(Variant(&["Hello", "world"][..]), &[32768u16, 16u16, 12u16][..]); + let m = m.append3(-1i32, &*format!("Hello world"), -3.14f64); + let m = m.append1((256i16, Variant(18_446_744_073_709_551_615u64))); + let m = m.append2(Path::new("/a/valid/path").unwrap(), Signature::new("a{sv}").unwrap()); + let mut z = HashMap::new(); + z.insert(123543u32, true); + z.insert(0u32, false); + let m = m.append1(Dict::new(&z)); + let sending = format!("{:?}", m.iter_init()); + println!("Sending {}", sending); + c.send(m).unwrap(); + + for n in c.iter(1000) { + match n { + ConnectionItem::MethodCall(m) => { + use super::Arg; + let receiving = format!("{:?}", m.iter_init()); + println!("Receiving {}", receiving); + assert_eq!(sending, receiving); + + assert_eq!(2000u16, m.get1().unwrap()); + assert_eq!(m.get2(), (Some(2000u16), Some(&[129u8, 5, 254][..]))); + assert_eq!(m.read2::<u16, bool>().unwrap_err(), + TypeMismatchError { position: 1, found: ArgType::Array, expected: ArgType::Boolean }); + + let mut g = m.iter_init(); + let e = g.read::<u32>().unwrap_err(); + assert_eq!(e.pos(), 0); + assert_eq!(e.expected_arg_type(), ArgType::UInt32); + assert_eq!(e.found_arg_type(), ArgType::UInt16); + + assert!(g.next() && g.next()); + let v: Variant<Iter> = g.get().unwrap(); + let mut viter = v.0; + assert_eq!(viter.arg_type(), Array::<&str,()>::ARG_TYPE); + let a: Array<&str, _> = viter.get().unwrap(); + assert_eq!(a.collect::<Vec<&str>>(), vec!["Hello", "world"]); + + assert!(g.next()); + assert_eq!(g.get::<u16>(), None); // It's an array, not a single u16 + assert!(g.next() && g.next() && g.next() && g.next()); + + assert_eq!(g.get(), Some((256i16, Variant(18_446_744_073_709_551_615u64)))); + assert!(g.next()); + assert_eq!(g.get(), Some(Path::new("/a/valid/path").unwrap())); + assert!(g.next()); + assert_eq!(g.get(), Some(Signature::new("a{sv}").unwrap())); + assert!(g.next()); + let d: Dict<u32, bool, _> = g.get().unwrap(); + let z2: HashMap<_, _> = d.collect(); + assert_eq!(z, z2); + break; + } + _ => println!("Got {:?}", n), + } + } + } +} diff --git a/third_party/rust/dbus/src/arg/variantstruct_impl.rs b/third_party/rust/dbus/src/arg/variantstruct_impl.rs new file mode 100644 index 0000000000..d58c99e098 --- /dev/null +++ b/third_party/rust/dbus/src/arg/variantstruct_impl.rs @@ -0,0 +1,242 @@ +use super::*; +use {message, Signature}; +use std::any; + +#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Ord, PartialOrd)] +/// A simple wrapper to specify a D-Bus variant. +/// +/// See the argument guide and module level documentation for details and examples. +pub struct Variant<T>(pub T); + +impl Variant<Box<RefArg>> { + /// Creates a new refarg from an Iter. Mainly for internal use. + pub fn new_refarg<'a>(i: &mut Iter<'a>) -> Option<Self> { + i.recurse(ArgType::Variant).and_then(|mut si| si.get_refarg()).map(|v| Variant(v)) + } +} + +impl Default for Variant<Box<RefArg>> { + // This is a bit silly, because there is no such thing as a default argument. + // Unfortunately due to a design mistake while making the SignalArgs trait, we'll + // have to work around that by adding a default implementation here. + // https://github.com/diwic/dbus-rs/issues/136 + fn default() -> Self { Variant(Box::new(0u8) as Box<RefArg>) } +} + +impl<T:Default> Default for Variant<T> { + fn default() -> Self { Variant(T::default()) } +} + + +impl<T> Arg for Variant<T> { + const ARG_TYPE: ArgType = ArgType::Variant; + fn signature() -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"v\0") } } +} + +impl<T: Arg + Append> Append for Variant<T> { + fn append(self, i: &mut IterAppend) { + let z = self.0; + i.append_container(ArgType::Variant, Some(T::signature().as_cstr()), |s| z.append(s)); + } +} + +impl Append for Variant<message::MessageItem> { + fn append(self, i: &mut IterAppend) { + let z = self.0; + let asig = z.signature(); + let sig = asig.as_cstr(); + i.append_container(ArgType::Variant, Some(&sig), |s| z.append(s)); + } +} + +impl Append for Variant<Box<RefArg>> { + fn append(self, i: &mut IterAppend) { + let z = self.0; + i.append_container(ArgType::Variant, Some(z.signature().as_cstr()), |s| z.append(s)); + } +} + +impl<'a, T: Get<'a>> Get<'a> for Variant<T> { + fn get(i: &mut Iter<'a>) -> Option<Variant<T>> { + i.recurse(ArgType::Variant).and_then(|mut si| si.get().map(|v| Variant(v))) + } +} + +impl<'a> Get<'a> for Variant<Iter<'a>> { + fn get(i: &mut Iter<'a>) -> Option<Variant<Iter<'a>>> { + i.recurse(ArgType::Variant).map(|v| Variant(v)) + } +} +/* +impl<'a> Get<'a> for Variant<Box<RefArg>> { + fn get(i: &mut Iter<'a>) -> Option<Variant<Box<RefArg>>> { + i.recurse(ArgType::Variant).and_then(|mut si| si.get_refarg().map(|v| Variant(v))) + } +} +*/ +impl<T: RefArg> RefArg for Variant<T> { + fn arg_type(&self) -> ArgType { ArgType::Variant } + fn signature(&self) -> Signature<'static> { unsafe { Signature::from_slice_unchecked(b"v\0") } } + fn append(&self, i: &mut IterAppend) { + let z = &self.0; + i.append_container(ArgType::Variant, Some(z.signature().as_cstr()), |s| z.append(s)); + } + #[inline] + fn as_any(&self) -> &any::Any where T: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where T: 'static { self } + #[inline] + fn as_i64(&self) -> Option<i64> { self.0.as_i64() } + #[inline] + fn as_u64(&self) -> Option<u64> { self.0.as_u64() } + #[inline] + fn as_f64(&self) -> Option<f64> { self.0.as_f64() } + #[inline] + fn as_str(&self) -> Option<&str> { self.0.as_str() } + #[inline] + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { + use std::iter; + let z: &RefArg = &self.0; + Some(Box::new(iter::once(z))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(Variant(self.0.box_clone())) } +} + +macro_rules! struct_impl { + ( $($n: ident $t: ident,)+ ) => { + +/// Tuples are represented as D-Bus structs. +impl<$($t: Arg),*> Arg for ($($t,)*) { + const ARG_TYPE: ArgType = ArgType::Struct; + fn signature() -> Signature<'static> { + let mut s = String::from("("); + $( s.push_str(&$t::signature()); )* + s.push_str(")"); + Signature::from(s) + } +} + +impl<$($t: Append),*> Append for ($($t,)*) { + fn append(self, i: &mut IterAppend) { + let ( $($n,)*) = self; + i.append_container(ArgType::Struct, None, |s| { $( $n.append(s); )* }); + } +} + +impl<'a, $($t: Get<'a>),*> Get<'a> for ($($t,)*) { + fn get(i: &mut Iter<'a>) -> Option<Self> { + let si = i.recurse(ArgType::Struct); + if si.is_none() { return None; } + let mut si = si.unwrap(); + let mut _valid_item = true; + $( + if !_valid_item { return None; } + let $n: Option<$t> = si.get(); + if $n.is_none() { return None; } + _valid_item = si.next(); + )* + Some(($( $n.unwrap(), )* )) + } +} + +impl<$($t: RefArg),*> RefArg for ($($t,)*) { + fn arg_type(&self) -> ArgType { ArgType::Struct } + fn signature(&self) -> Signature<'static> { + let &( $(ref $n,)*) = self; + let mut s = String::from("("); + $( s.push_str(&$n.signature()); )* + s.push_str(")"); + Signature::from(s) + } + fn append(&self, i: &mut IterAppend) { + let &( $(ref $n,)*) = self; + i.append_container(ArgType::Struct, None, |s| { $( $n.append(s); )* }); + } + fn as_any(&self) -> &any::Any where Self: 'static { self } + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { + let &( $(ref $n,)*) = self; + let v = vec!( + $( $n as &RefArg, )* + ); + Some(Box::new(v.into_iter())) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + let &( $(ref $n,)*) = self; + let mut z = vec!(); + $( z.push($n.box_clone()); )* + Box::new(z) + } +} + + +}} // macro_rules end + +struct_impl!(a A,); +struct_impl!(a A, b B,); +struct_impl!(a A, b B, c C,); +struct_impl!(a A, b B, c C, d D,); +struct_impl!(a A, b B, c C, d D, e E,); +struct_impl!(a A, b B, c C, d D, e E, f F,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J, k K,); +struct_impl!(a A, b B, c C, d D, e E, f F, g G, h H, i I, j J, k K, l L,); + +impl RefArg for Vec<Box<RefArg>> { + fn arg_type(&self) -> ArgType { ArgType::Struct } + fn signature(&self) -> Signature<'static> { + let mut s = String::from("("); + for z in self { + s.push_str(&z.signature()); + } + s.push_str(")"); + Signature::from(s) + } + fn append(&self, i: &mut IterAppend) { + i.append_container(ArgType::Struct, None, |s| { + for z in self { z.append(s); } + }); + } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + fn as_iter<'a>(&'a self) -> Option<Box<Iterator<Item=&'a RefArg> + 'a>> { + Some(Box::new(self.iter().map(|b| &**b))) + } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { + let t: Vec<Box<RefArg + 'static>> = self.iter().map(|x| x.box_clone()).collect(); + Box::new(t) + } +} + +impl Append for message::MessageItem { + fn append(self, i: &mut IterAppend) { + message::append_messageitem(&mut i.0, &self) + } +} + +impl<'a> Get<'a> for message::MessageItem { + fn get(i: &mut Iter<'a>) -> Option<Self> { + message::get_messageitem(&mut i.0) + } +} + +impl RefArg for message::MessageItem { + fn arg_type(&self) -> ArgType { ArgType::from_i32(self.array_type()).unwrap() } + fn signature(&self) -> Signature<'static> { message::MessageItem::signature(&self) } + fn append(&self, i: &mut IterAppend) { message::append_messageitem(&mut i.0, self) } + #[inline] + fn as_any(&self) -> &any::Any where Self: 'static { self } + #[inline] + fn as_any_mut(&mut self) -> &mut any::Any where Self: 'static { self } + #[inline] + fn box_clone(&self) -> Box<RefArg + 'static> { Box::new(self.clone()) } +} + |