use crate::strings::{Signature, Path, Interface, BusName};
use crate::arg;
use crate::arg::{Iter, IterAppend, Arg, ArgType, OwnedFd};
use std::ffi::CStr;
use std::{ops, any};
use crate::{ffidisp::Connection, Message, Error};
use std::collections::BTreeMap;
use std::convert::TryFrom;
#[derive(Debug,Copy,Clone)]
pub enum ArrayError {
EmptyArray,
DifferentElementTypes,
InvalidSignature,
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct MessageItemArray {
v: Vec<MessageItem>,
sig: Signature<'static>,
}
impl MessageItemArray {
pub fn new(v: Vec<MessageItem>, sig: Signature<'static>) -> Result<MessageItemArray, ArrayError> {
let a = MessageItemArray {v: v, sig: sig };
if a.sig.as_bytes()[0] != ffi::DBUS_TYPE_ARRAY as u8 { return Err(ArrayError::InvalidSignature) }
{
let esig = a.element_signature();
for i in &a.v {
if i.signature().as_cstr() != esig { return Err(ArrayError::DifferentElementTypes) }
}
}
Ok(a)
}
fn element_signature(&self) -> &CStr {
let z = &self.sig.as_cstr().to_bytes_with_nul()[1..];
unsafe { CStr::from_bytes_with_nul_unchecked(z) }
}
fn make_sig(m: &MessageItem) -> Signature<'static> {
Signature::new(format!("a{}", m.signature())).unwrap()
}
pub fn signature(&self) -> &Signature<'static> { &self.sig }
pub fn into_vec(self) -> Vec<MessageItem> { self.v }
}
impl ops::Deref for MessageItemArray {
type Target = [MessageItem];
fn deref(&self) -> &Self::Target { &self.v }
}
impl arg::Append for MessageItemArray {
fn append_by_ref(&self, i: &mut IterAppend) {
i.append_container(ArgType::Array, Some(self.element_signature()), |s| {
for a in &self.v { a.append_by_ref(s) }
});
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
pub struct MessageItemDict {
v: Vec<(MessageItem, MessageItem)>,
sig: Signature<'static>,
}
impl MessageItemDict {
pub fn new(v: Vec<(MessageItem, MessageItem)>, keysig: Signature<'static>, valuesig: Signature<'static>) -> Result<MessageItemDict, ArrayError> {
let sig = Signature::from(format!("a{{{}{}}}", keysig, valuesig));
let a = MessageItemDict {v: v, sig: sig };
for (k, v) in &a.v {
if keysig != k.signature() || valuesig != v.signature() {
return Err(ArrayError::DifferentElementTypes);
}
}
Ok(a)
}
fn element_signature(&self) -> &CStr {
let z = &self.sig.as_cstr().to_bytes_with_nul()[1..];
unsafe { CStr::from_bytes_with_nul_unchecked(z) }
}
pub fn signature(&self) -> &Signature<'static> { &self.sig }
pub fn into_vec(self) -> Vec<(MessageItem, MessageItem)> { self.v }
}
impl ops::Deref for MessageItemDict {
type Target = [(MessageItem, MessageItem)];
fn deref(&self) -> &Self::Target { &self.v }
}
impl arg::Append for MessageItemDict {
fn append_by_ref(&self, i: &mut IterAppend) {
i.append_container(ArgType::Array, Some(self.element_signature()), |s| {
for (k, v) in &self.v {
s.append_container(ArgType::DictEntry, None, |ss| {
k.append_by_ref(ss);
v.append_by_ref(ss);
});
}
});
}
}
#[derive(Debug, PartialEq, PartialOrd, Clone)]
pub enum MessageItem {
Array(MessageItemArray),
Struct(Vec<MessageItem>),
Variant(Box<MessageItem>),
Dict(MessageItemDict),
ObjectPath(Path<'static>),
Signature(Signature<'static>),
Str(String),
Bool(bool),
Byte(u8),
Int16(i16),
Int32(i32),
Int64(i64),
UInt16(u16),
UInt32(u32),
UInt64(u64),
Double(f64),
UnixFd(OwnedFd),
}
impl MessageItem {
pub fn signature(&self) -> Signature<'static> {
use crate::arg::Variant;
match self {
MessageItem::Str(_) => <String as Arg>::signature(),
MessageItem::Bool(_) => <bool as Arg>::signature(),
MessageItem::Byte(_) => <u8 as Arg>::signature(),
MessageItem::Int16(_) => <i16 as Arg>::signature(),
MessageItem::Int32(_) => <i32 as Arg>::signature(),
MessageItem::Int64(_) => <i64 as Arg>::signature(),
MessageItem::UInt16(_) => <u16 as Arg>::signature(),
MessageItem::UInt32(_) => <u32 as Arg>::signature(),
MessageItem::UInt64(_) => <u64 as Arg>::signature(),
MessageItem::Double(_) => <f64 as Arg>::signature(),
MessageItem::Array(ref a) => a.sig.clone(),
MessageItem::Struct(ref s) => Signature::new(format!("({})", s.iter().fold(String::new(), |s, i| s + &*i.signature()))).unwrap(),
MessageItem::Variant(_) => <Variant<u8> as Arg>::signature(),
MessageItem::Dict(ref a) => a.sig.clone(),
MessageItem::ObjectPath(_) => <Path as Arg>::signature(),
MessageItem::Signature(_) => <Signature as Arg>::signature(),
MessageItem::UnixFd(_) => <OwnedFd as Arg>::signature(),
}
}
pub fn arg_type(&self) -> arg::ArgType {
match self {
MessageItem::Str(_) => ArgType::String,
MessageItem::Bool(_) => ArgType::Boolean,
MessageItem::Byte(_) => ArgType::Byte,
MessageItem::Int16(_) => ArgType::Int16,
MessageItem::Int32(_) => ArgType::Int32,
MessageItem::Int64(_) => ArgType::Int64,
MessageItem::UInt16(_) => ArgType::UInt16,
MessageItem::UInt32(_) => ArgType::UInt32,
MessageItem::UInt64(_) => ArgType::UInt64,
MessageItem::Double(_) => ArgType::Double,
MessageItem::Array(_) => ArgType::Array,
MessageItem::Struct(_) => ArgType::Struct,
MessageItem::Variant(_) => ArgType::Variant,
MessageItem::Dict(_) => ArgType::Array,
MessageItem::ObjectPath(_) => ArgType::ObjectPath,
MessageItem::Signature(_) => ArgType::Signature,
MessageItem::UnixFd(_) => ArgType::UnixFd,
}
}
pub fn from_dict<E, I: Iterator<Item=Result<(String, MessageItem),E>>>(i: I) -> Result<MessageItem, E> {
let mut v = Vec::new();
for r in i {
let (s, vv) = r?;
v.push((s.into(), Box::new(vv).into()));
}
Ok(MessageItem::Dict(MessageItemDict::new(v, Signature::new("s").unwrap(), Signature::new("v").unwrap()).unwrap()))
}
pub fn new_array(v: Vec<MessageItem>) -> Result<MessageItem, ArrayError> {
if v.is_empty() {
return Err(ArrayError::EmptyArray);
}
let s = MessageItemArray::make_sig(&v[0]);
Ok(MessageItem::Array(MessageItemArray::new(v, s)?))
}
pub fn new_dict(v: Vec<(MessageItem, MessageItem)>) -> Result<MessageItem, ArrayError> {
if v.is_empty() {
return Err(ArrayError::EmptyArray);
}
let (s1, s2) = (v[0].0.signature(), v[0].1.signature());
Ok(MessageItem::Dict(MessageItemDict::new(v, s1, s2)?))
}
pub fn inner<'a, T: TryFrom<&'a MessageItem>>(&'a self) -> Result<T, T::Error> {
T::try_from(self)
}
fn new_array2<D, I>(i: I) -> MessageItem
where D: Into<MessageItem>, D: Default, I: Iterator<Item=D> {
let v: Vec<MessageItem> = i.map(|ii| ii.into()).collect();
let s = {
let d;
let t = if v.is_empty() { d = D::default().into(); &d } else { &v[0] };
MessageItemArray::make_sig(t)
};
MessageItem::Array(MessageItemArray::new(v, s).unwrap())
}
fn new_dict2<K, V, I>(i: I) -> MessageItem
where K: Into<MessageItem> + Default, V: Into<MessageItem> + Default, I: Iterator<Item=(K, V)> {
let v: Vec<(MessageItem, MessageItem)> = i.map(|(k, v)| (k.into(), v.into())).collect();
let (kt, vt) = if v.is_empty() {
let kd = K::default().into();
let vd = V::default().into();
(kd.signature(), vd.signature())
} else { (v[0].0.signature(), v[0].1.signature()) };
MessageItem::Dict(MessageItemDict::new(v, kt, vt).unwrap())
}
}
macro_rules! msgitem_convert {
($t: ty, $s: ident) => {
impl From<$t> for MessageItem { fn from(i: $t) -> MessageItem { MessageItem::$s(i) } }
impl<'a> TryFrom<&'a MessageItem> for $t {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<$t,()> {
if let MessageItem::$s(b) = i { Ok(*b) } else { Err(()) }
}
}
}
}
msgitem_convert!(u8, Byte);
msgitem_convert!(u64, UInt64);
msgitem_convert!(u32, UInt32);
msgitem_convert!(u16, UInt16);
msgitem_convert!(i16, Int16);
msgitem_convert!(i32, Int32);
msgitem_convert!(i64, Int64);
msgitem_convert!(f64, Double);
msgitem_convert!(bool, Bool);
impl<'a, T> From<&'a [T]> for MessageItem
where T: Into<MessageItem> + Clone + Default {
fn from(i: &'a [T]) -> MessageItem {
MessageItem::new_array2(i.iter().cloned())
}
}
impl<'a, T1, T2> From<&'a [(T1, T2)]> for MessageItem
where T1: Into<MessageItem> + Clone + Default, T2: Into<MessageItem> + Clone + Default {
fn from(i: &'a [(T1, T2)]) -> MessageItem {
MessageItem::new_dict2(i.iter().cloned())
}
}
impl<'a> From<&'a str> for MessageItem { fn from(i: &str) -> MessageItem { MessageItem::Str(i.to_string()) } }
impl From<String> for MessageItem { fn from(i: String) -> MessageItem { MessageItem::Str(i) } }
impl From<Path<'static>> for MessageItem { fn from(i: Path<'static>) -> MessageItem { MessageItem::ObjectPath(i) } }
impl From<Signature<'static>> for MessageItem { fn from(i: Signature<'static>) -> MessageItem { MessageItem::Signature(i) } }
impl From<OwnedFd> for MessageItem { fn from(i: OwnedFd) -> MessageItem { MessageItem::UnixFd(i) } }
impl From<Box<MessageItem>> for MessageItem {
fn from(i: Box<MessageItem>) -> MessageItem { MessageItem::Variant(i) }
}
impl<'a> TryFrom<&'a MessageItem> for &'a str {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a str, Self::Error> {
match i {
MessageItem::Str(ref b) => Ok(b),
MessageItem::ObjectPath(ref b) => Ok(b),
MessageItem::Signature(ref b) => Ok(b),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a MessageItem> for &'a String {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a String,()> { if let MessageItem::Str(b) = i { Ok(b) } else { Err(()) } }
}
impl<'a> TryFrom<&'a MessageItem> for &'a Path<'static> {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a Path<'static>,()> { if let MessageItem::ObjectPath(b) = i { Ok(b) } else { Err(()) } }
}
impl<'a> TryFrom<&'a MessageItem> for &'a Signature<'static> {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a Signature<'static>,()> { if let MessageItem::Signature(b) = i { Ok(b) } else { Err(()) } }
}
impl<'a> TryFrom<&'a MessageItem> for &'a Box<MessageItem> {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a Box<MessageItem>,()> { if let MessageItem::Variant(b) = i { Ok(b) } else { Err(()) } }
}
impl<'a> TryFrom<&'a MessageItem> for &'a Vec<MessageItem> {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a Vec<MessageItem>,()> {
match i {
MessageItem::Array(b) => Ok(&b.v),
MessageItem::Struct(b) => Ok(b),
_ => Err(()),
}
}
}
impl<'a> TryFrom<&'a MessageItem> for &'a [MessageItem] {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a [MessageItem],()> { i.inner::<&Vec<MessageItem>>().map(|s| &**s) }
}
impl<'a> TryFrom<&'a MessageItem> for &'a OwnedFd {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a OwnedFd,()> { if let MessageItem::UnixFd(ref b) = i { Ok(b) } else { Err(()) } }
}
impl<'a> TryFrom<&'a MessageItem> for &'a [(MessageItem, MessageItem)] {
type Error = ();
fn try_from(i: &'a MessageItem) -> Result<&'a [(MessageItem, MessageItem)],()> {
if let MessageItem::Dict(ref d) = i { Ok(&*d.v) } else { Err(()) }
}
}
impl arg::Append for MessageItem {
fn append_by_ref(&self, i: &mut IterAppend) {
match self {
MessageItem::Str(a) => a.append_by_ref(i),
MessageItem::Bool(a) => a.append_by_ref(i),
MessageItem::Byte(a) => a.append_by_ref(i),
MessageItem::Int16(a) => a.append_by_ref(i),
MessageItem::Int32(a) => a.append_by_ref(i),
MessageItem::Int64(a) => a.append_by_ref(i),
MessageItem::UInt16(a) => a.append_by_ref(i),
MessageItem::UInt32(a) => a.append_by_ref(i),
MessageItem::UInt64(a) => a.append_by_ref(i),
MessageItem::Double(a) => a.append_by_ref(i),
MessageItem::Array(a) => a.append_by_ref(i),
MessageItem::Struct(a) => i.append_container(ArgType::Struct, None, |s| {
for v in a { v.append_by_ref(s); }
}),
MessageItem::Variant(a) => {
i.append_container(ArgType::Variant, Some(a.signature().as_cstr()), |s| a.append_by_ref(s))
},
MessageItem::Dict(a) => a.append_by_ref(i),
MessageItem::ObjectPath(a) => a.append_by_ref(i),
MessageItem::Signature(a) => a.append_by_ref(i),
MessageItem::UnixFd(a) => a.append_by_ref(i),
}
}
}
impl<'a> arg::Get<'a> for MessageItem {
fn get(i: &mut Iter<'a>) -> Option<Self> {
Some(match i.arg_type() {
ArgType::Array => {
let mut s = i.recurse(ArgType::Array).unwrap();
if i.signature().as_bytes()[1] == b'{' { let mut v = vec!();
while s.arg_type() == ArgType::DictEntry {
let mut ss = s.recurse(ArgType::DictEntry).unwrap();
let kk = MessageItem::get(&mut ss).unwrap();
ss.next();
let vv = MessageItem::get(&mut ss).unwrap();
v.push((kk, vv));
s.next();
};
MessageItem::Dict(MessageItemDict { v: v, sig: i.signature() })
} else {
let mut v = vec!();
while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); };
MessageItem::Array(MessageItemArray { v: v, sig: i.signature() })
}
},
ArgType::Variant => MessageItem::Variant({
let mut s = i.recurse(ArgType::Variant).unwrap();
Box::new(MessageItem::get(&mut s).unwrap())
}),
ArgType::Boolean => MessageItem::Bool(i.get::<bool>().unwrap()),
ArgType::Invalid => return None,
ArgType::String => MessageItem::Str(i.get::<String>().unwrap()),
ArgType::DictEntry => return None,
ArgType::Byte => MessageItem::Byte(i.get::<u8>().unwrap()),
ArgType::Int16 => MessageItem::Int16(i.get::<i16>().unwrap()),
ArgType::UInt16 => MessageItem::UInt16(i.get::<u16>().unwrap()),
ArgType::Int32 => MessageItem::Int32(i.get::<i32>().unwrap()),
ArgType::UInt32 => MessageItem::UInt32(i.get::<u32>().unwrap()),
ArgType::Int64 => MessageItem::Int64(i.get::<i64>().unwrap()),
ArgType::UInt64 => MessageItem::UInt64(i.get::<u64>().unwrap()),
ArgType::Double => MessageItem::Double(i.get::<f64>().unwrap()),
ArgType::UnixFd => MessageItem::UnixFd(i.get::<OwnedFd>().unwrap()),
ArgType::Struct => MessageItem::Struct({
let mut s = i.recurse(ArgType::Struct).unwrap();
let mut v = vec!();
while let Some(mi) = MessageItem::get(&mut s) { v.push(mi); s.next(); };
v
}),
ArgType::ObjectPath => MessageItem::ObjectPath(i.get::<Path>().unwrap().into_static()),
ArgType::Signature => MessageItem::Signature(i.get::<Signature>().unwrap().into_static()),
})
}
}
impl arg::RefArg for MessageItem {
fn arg_type(&self) -> ArgType { MessageItem::arg_type(&self) }
fn signature(&self) -> Signature<'static> { MessageItem::signature(&self) }
fn append(&self, i: &mut IterAppend) { arg::Append::append_by_ref(self, i) }
#[inline]
fn as_any(&self) -> &dyn any::Any where Self: 'static { self }
#[inline]
fn as_any_mut(&mut self) -> &mut dyn any::Any where Self: 'static { self }
#[inline]
fn box_clone(&self) -> Box<dyn arg::RefArg + 'static> { Box::new(self.clone()) }
}
impl arg::Append for arg::Variant<MessageItem> {
fn append_by_ref(&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_by_ref(s));
}
}
pub struct Props<'a> {
name: BusName<'a>,
path: Path<'a>,
interface: Interface<'a>,
timeout_ms: i32,
conn: &'a Connection,
}
impl<'a> Props<'a> {
pub fn new<N, P, I>(conn: &'a Connection, name: N, path: P, interface: I, timeout_ms: i32) -> Props<'a>
where N: Into<BusName<'a>>, P: Into<Path<'a>>, I: Into<Interface<'a>> {
Props {
name: name.into(),
path: path.into(),
interface: interface.into(),
timeout_ms: timeout_ms,
conn: conn,
}
}
pub fn get(&self, propname: &str) -> Result<MessageItem, Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"Get".into());
m.append_items(&[self.interface.to_string().into(), propname.to_string().into()]);
let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
let reply = r.as_result()?.get_items();
if reply.len() == 1 {
if let MessageItem::Variant(ref v) = reply[0] {
return Ok((**v).clone())
}
}
let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply);
Err(Error::new_custom("InvalidReply", &f))
}
pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"Set".into());
m.append_items(&[self.interface.to_string().into(), propname.to_string().into(), Box::new(value).into()]);
let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
r.as_result()?;
Ok(())
}
pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> {
let mut m = Message::method_call(&self.name, &self.path,
&"org.freedesktop.DBus.Properties".into(), &"GetAll".into());
m.append_items(&[self.interface.to_string().into()]);
let mut r = self.conn.send_with_reply_and_block(m, self.timeout_ms)?;
let reply = r.as_result()?.get_items();
(|| {
if reply.len() != 1 { return Err(()) };
let mut tree = BTreeMap::new();
let a: &[(MessageItem, MessageItem)] = reply[0].inner()?;
for (k, v) in a.iter() {
let (k, v): (&String, &Box<MessageItem>) = (k.inner()?, v.inner()?);
tree.insert(k.clone(), *v.clone());
}
Ok(tree)
})().map_err(|_| {
let f = format!("Invalid reply for property GetAll: '{:?}'", reply);
Error::new_custom("InvalidReply", &f)
})
}
}
pub struct PropHandler<'a> {
p: Props<'a>,
map: BTreeMap<String, MessageItem>,
}
impl<'a> PropHandler<'a> {
pub fn new(p: Props) -> PropHandler {
PropHandler { p: p, map: BTreeMap::new() }
}
pub fn get_all(&mut self) -> Result<(), Error> {
self.map = self.p.get_all()?;
Ok(())
}
pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map }
pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map }
pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> {
let v = self.p.get(propname)?;
self.map.insert(propname.to_string(), v);
Ok(self.map.get(propname).unwrap())
}
pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> {
self.p.set(propname, value.clone())?;
self.map.insert(propname.to_string(), value);
Ok(())
}
}
#[cfg(test)]
mod test {
extern crate tempfile;
use crate::{Message, MessageType, Path, Signature};
use libc;
use crate::arg::messageitem::MessageItem;
use crate::arg::OwnedFd;
use crate::ffidisp::{Connection, BusType};
#[test]
fn unix_fd() {
use std::io::prelude::*;
use std::io::SeekFrom;
use std::fs::OpenOptions;
use std::os::unix::io::AsRawFd;
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/hello").unwrap();
let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
let tempdir = tempfile::Builder::new().prefix("dbus-rs-test").tempdir().unwrap();
let mut filename = tempdir.path().to_path_buf();
filename.push("test");
println!("Creating file {:?}", filename);
let mut file = OpenOptions::new().create(true).read(true).write(true).open(&filename).unwrap();
file.write_all(b"z").unwrap();
file.seek(SeekFrom::Start(0)).unwrap();
let ofd = OwnedFd::new(file.as_raw_fd());
m.append_items(&[MessageItem::UnixFd(ofd.clone())]);
println!("Sending {:?}", m.get_items());
c.send(m).unwrap();
loop { for n in c.incoming(1000) {
if n.msg_type() == MessageType::MethodCall {
let z: OwnedFd = n.read1().unwrap();
println!("Got {:?}", z);
let mut q: libc::c_char = 100;
assert_eq!(1, unsafe { libc::read(z.as_raw_fd(), &mut q as *mut _ as *mut libc::c_void, 1) });
assert_eq!(q, 'z' as libc::c_char);
return;
} else {
println!("Got {:?}", n);
}
}}
}
#[test]
fn message_types() {
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/hello").unwrap();
let mut m = Message::new_method_call(&c.unique_name(), "/hello", "com.example.hello", "Hello").unwrap();
m.append_items(&[
2000u16.into(),
MessageItem::new_array(vec!(129u8.into())).unwrap(),
["Hello", "world"][..].into(),
987654321u64.into(),
(-1i32).into(),
format!("Hello world").into(),
(-3.14f64).into(),
MessageItem::Struct(vec!(256i16.into())),
Path::new("/some/path").unwrap().into(),
MessageItem::new_dict(vec!((123543u32.into(), true.into()).into())).unwrap()
]);
let sending = format!("{:?}", m.get_items());
println!("Sending {}", sending);
c.send(m).unwrap();
loop { for n in c.incoming(1000) {
if n.msg_type() == MessageType::MethodCall {
let receiving = format!("{:?}", n.get_items());
println!("Receiving {}", receiving);
assert_eq!(sending, receiving);
return;
} else {
println!("Got {:?}", n);
}
}}
}
#[test]
fn dict_of_dicts() {
use std::collections::BTreeMap;
let officeactions: BTreeMap<&'static str, MessageItem> = BTreeMap::new();
let mut officethings = BTreeMap::new();
officethings.insert("pencil", 2u16.into());
officethings.insert("paper", 5u16.into());
let mut homethings = BTreeMap::new();
homethings.insert("apple", 11u16.into());
let mut homeifaces = BTreeMap::new();
homeifaces.insert("getThings", homethings);
let mut officeifaces = BTreeMap::new();
officeifaces.insert("getThings", officethings);
officeifaces.insert("getActions", officeactions);
let mut paths = BTreeMap::new();
paths.insert("/hello/office", officeifaces);
paths.insert("/hello/home", homeifaces);
println!("Original treemap: {:?}", paths);
let m = MessageItem::new_dict(paths.iter().map(
|(path, ifaces)| (MessageItem::ObjectPath(Path::new(*path).unwrap()),
MessageItem::new_dict(ifaces.iter().map(
|(iface, props)| (iface.to_string().into(),
MessageItem::from_dict::<(),_>(props.iter().map(
|(name, value)| Ok((name.to_string(), value.clone()))
)).unwrap()
).into()
).collect()).unwrap()
).into()
).collect()).unwrap();
println!("As MessageItem: {:?}", m);
assert_eq!(&*m.signature(), "a{oa{sa{sv}}}");
let c = Connection::get_private(BusType::Session).unwrap();
c.register_object_path("/hello").unwrap();
let mut msg = Message::new_method_call(&c.unique_name(), "/hello", "org.freedesktop.DBusObjectManager", "GetManagedObjects").unwrap();
msg.append_items(&[m]);
let sending = format!("{:?}", msg.get_items());
println!("Sending {}", sending);
c.send(msg).unwrap();
loop { for n in c.incoming(1000) {
if n.msg_type() == MessageType::MethodCall {
let receiving = format!("{:?}", n.get_items());
println!("Receiving {}", receiving);
assert_eq!(sending, receiving);
return;
} else {
println!("Got {:?}", n);
}
} }
}
#[test]
fn issue24() {
let c = Connection::get_private(BusType::Session).unwrap();
let mut m = Message::new_method_call("org.test.rust", "/", "org.test.rust", "Test").unwrap();
let a = MessageItem::from("test".to_string());
let b = MessageItem::from("test".to_string());
let foo = MessageItem::Struct(vec!(a, b));
let bar = foo.clone();
let args = [MessageItem::new_array(vec!(foo, bar)).unwrap()];
println!("{:?}", args);
m.append_items(&args);
c.send(m).unwrap();
}
#[test]
fn test_get_hostname1_prop() {
use super::Props;
let c = Connection::new_system().unwrap();
let p = Props::new(&c, "org.freedesktop.hostname1", "/org/freedesktop/hostname1",
"org.freedesktop.hostname1", 10000);
let v = p.get("StaticHostname").unwrap();
let vall = p.get_all().unwrap();
let v2 = vall.get("StaticHostname").unwrap();
assert_eq!(&v, &*v2);
match v {
MessageItem::Str(ref s) => { println!("StaticHostname is {}", s); }
_ => { panic!("Invalid Get: {:?}", v); }
};
}
#[test]
fn message_listnames() {
let c = Connection::get_private(BusType::Session).unwrap();
let m = Message::method_call(&"org.freedesktop.DBus".into(), &"/".into(),
&"org.freedesktop.DBus".into(), &"ListNames".into());
let r = c.send_with_reply_and_block(m, 2000).unwrap();
let reply = r.get_items();
println!("{:?}", reply);
}
#[test]
fn message_namehasowner() {
let c = Connection::get_private(BusType::Session).unwrap();
let mut m = Message::new_method_call("org.freedesktop.DBus", "/", "org.freedesktop.DBus", "NameHasOwner").unwrap();
m.append_items(&[MessageItem::Str("org.freedesktop.DBus".to_string())]);
let r = c.send_with_reply_and_block(m, 2000).unwrap();
let reply = r.get_items();
println!("{:?}", reply);
assert_eq!(reply, vec!(MessageItem::Bool(true)));
}
#[test]
fn message_inner_str() {
let ob = MessageItem::ObjectPath("/path".into());
assert_eq!("/path", ob.inner::<&str>().unwrap());
let ob = MessageItem::ObjectPath("/path".into());
assert_ne!("/path/another", ob.inner::<&str>().unwrap());
let ob = MessageItem::Str("String".into());
assert_eq!("String", ob.inner::<&str>().unwrap());
let ob = MessageItem::Str("String".into());
assert_ne!("StringDiff", ob.inner::<&str>().unwrap());
let ob = MessageItem::Signature(Signature::make::<i32>());
assert_eq!("i", ob.inner::<&str>().unwrap());
let ob = MessageItem::Signature(Signature::make::<u32>());
assert_ne!("i", ob.inner::<&str>().unwrap());
}
}