1 #![allow(dead_code)]
2 
3 use {MessageItem, Message, MessageType, Connection, ConnectionItem, Error, ErrorName};
4 use {Signature, Member, Path};
5 use Interface as IfaceName;
6 use std::cell::RefCell;
7 use std::sync::{Arc, Mutex};
8 use std::collections::BTreeMap;
9 use std::marker::PhantomData;
10 use std::ffi::CString;
11 use std::fmt;
12 
13 type ArcMap<K, V> = BTreeMap<Arc<K>, Arc<V>>;
14 
15 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
16 /// A D-Bus Argument.
17 pub struct Argument(Option<String>, Signature);
18 
19 impl Argument {
20     /// Create a new Argument.
new(name: Option<String>, sig: Signature) -> Argument21     pub fn new(name: Option<String>, sig: Signature) -> Argument { Argument(name, sig) }
22 
introspect(&self, indent: &str, dir: &str) -> String23     fn introspect(&self, indent: &str, dir: &str) -> String {
24         let n = self.0.as_ref().map(|n| format!("name=\"{}\" ", n)).unwrap_or("".into());
25         format!("{}<arg {}type=\"{}\"{}/>\n", indent, n, self.1, dir)
26     }
introspect_all(args: &[Argument], indent: &str, dir: &str) -> String27     fn introspect_all(args: &[Argument], indent: &str, dir: &str) -> String {
28         args.iter().fold("".to_string(), |aa, az| format!("{}{}", aa, az.introspect(indent, dir)))
29     }
30 }
31 
32 // Doesn't work, conflicting impls
33 // impl<S: Into<Signature>> From<S> for Argument
34 
35 impl From<Signature> for Argument {
from(t: Signature) -> Argument36     fn from(t: Signature) -> Argument { Argument(None, t) }
37 }
38 
39 impl<'a> From<&'a str> for Argument {
from(t: &str) -> Argument40     fn from(t: &str) -> Argument { Argument(None, t.into()) }
41 }
42 
43 impl<N: Into<String>, S: Into<Signature>> From<(N, S)> for Argument {
from((n, s): (N, S)) -> Argument44     fn from((n, s): (N, S)) -> Argument { Argument(Some(n.into()), s.into()) }
45 }
46 
47 #[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
48 /// A D-Bus Method Error.
49 pub struct MethodErr(ErrorName, String);
50 
51 impl MethodErr {
52     /// Create an Invalid Args MethodErr.
invalid_arg<T: fmt::Debug>(a: &T) -> MethodErr53     pub fn invalid_arg<T: fmt::Debug>(a: &T) -> MethodErr {
54         ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)).into()
55     }
56     /// Create a MethodErr that there are not enough arguments given.
no_arg() -> MethodErr57     pub fn no_arg() -> MethodErr {
58         ("org.freedesktop.DBus.Error.InvalidArgs", "Not enough arguments").into()
59     }
60     /// Create a MethodErr that the method failed in the way specified.
failed<T: fmt::Display>(a: &T) -> MethodErr61     pub fn failed<T: fmt::Display>(a: &T) -> MethodErr {
62         ("org.freedesktop.DBus.Error.Failed", a.to_string()).into()
63     }
64     /// Create a MethodErr that the Interface was unknown.
no_interface<T: fmt::Display>(a: &T) -> MethodErr65     pub fn no_interface<T: fmt::Display>(a: &T) -> MethodErr {
66         ("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", a)).into()
67     }
68     /// Create a MethodErr that the Property was unknown.
no_property<T: fmt::Display>(a: &T) -> MethodErr69     pub fn no_property<T: fmt::Display>(a: &T) -> MethodErr {
70         ("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", a)).into()
71     }
72     /// Create a MethodErr that the Property was read-only.
ro_property<T: fmt::Display>(a: &T) -> MethodErr73     pub fn ro_property<T: fmt::Display>(a: &T) -> MethodErr {
74         ("org.freedesktop.DBus.Error.PropertyReadOnly", format!("Property {} is read only", a)).into()
75     }
76 }
77 
78 impl<T: Into<ErrorName>, M: Into<String>> From<(T, M)> for MethodErr {
from((t, m): (T, M)) -> MethodErr79     fn from((t, m): (T, M)) -> MethodErr { MethodErr(t.into(), m.into()) }
80 }
81 
82 /// Result containing the Messages returned from the Method, or a MethodErr.
83 pub type MethodResult = Result<Vec<Message>, MethodErr>;
84 
85 /// A MethodType that wraps an Fn function
86 pub struct MethodFn<'a>(Box<Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + 'a>);
87 /// A MethodType that wraps an FnMut function. Calling this recursively will cause a refcell panic.
88 pub struct MethodFnMut<'a>(Box<RefCell<FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + 'a>>);
89 /// A MethodType that wraps an Fn+Send+Sync function, so it can be called from several threads in parallel.
90 pub struct MethodSync(Box<Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static>);
91 
92 impl<'a> fmt::Debug for MethodFn<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result93     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Fn>") }
94 }
95 
96 impl<'a> fmt::Debug for MethodFnMut<'a> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result97     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<FnMut>") }
98 }
99 
100 impl fmt::Debug for MethodSync {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result101     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Fn + Send + Sync>") }
102 }
103 
104 /// A helper trait used internally to make the tree generic over MethodFn, MethodFnMut and MethodSync.
105 pub trait MethodType: Sized {
call_method(&self, m: &Message, o: &ObjectPath<Self>, i: &Tree<Self>) -> MethodResult106     fn call_method(&self, m: &Message, o: &ObjectPath<Self>, i: &Tree<Self>) -> MethodResult;
box_method<H>(h: H) -> Self where H: Fn(&Message, &ObjectPath<Self>, &Tree<Self>) -> MethodResult + Send + Sync + 'static107     fn box_method<H>(h: H) -> Self
108     where H: Fn(&Message, &ObjectPath<Self>, &Tree<Self>) -> MethodResult + Send + Sync + 'static;
109 }
110 
111 impl<'a> MethodType for MethodFn<'a> {
call_method(&self, m: &Message, o: &ObjectPath<MethodFn<'a>>, i: &Tree<MethodFn<'a>>) -> MethodResult112     fn call_method(&self, m: &Message, o: &ObjectPath<MethodFn<'a>>, i: &Tree<MethodFn<'a>>) -> MethodResult { self.0(m, o, i) }
113 
box_method<H>(h: H) -> Self where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + Send + Sync + 'static114     fn box_method<H>(h: H) -> Self
115     where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + Send + Sync + 'static {
116         MethodFn(Box::new(h))
117     }
118 }
119 
120 impl MethodType for MethodSync {
call_method(&self, m: &Message, o: &ObjectPath<MethodSync>, i: &Tree<MethodSync>) -> MethodResult121     fn call_method(&self, m: &Message, o: &ObjectPath<MethodSync>, i: &Tree<MethodSync>) -> MethodResult { self.0(m, o, i) }
122 
box_method<H>(h: H) -> Self where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static123     fn box_method<H>(h: H) -> Self
124     where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static {
125         MethodSync(Box::new(h))
126     }
127 }
128 
129 impl<'a> MethodType for MethodFnMut<'a> {
call_method(&self, m: &Message, o: &ObjectPath<MethodFnMut<'a>>, i: &Tree<MethodFnMut<'a>>) -> MethodResult130     fn call_method(&self, m: &Message, o: &ObjectPath<MethodFnMut<'a>>, i: &Tree<MethodFnMut<'a>>) -> MethodResult {
131         let mut z = self.0.borrow_mut();
132         (&mut *z)(m, o, i)
133     }
134 
box_method<H>(h: H) -> Self where H: Fn(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + Send + Sync + 'static135     fn box_method<H>(h: H) -> Self
136     where H: Fn(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + Send + Sync + 'static {
137         MethodFnMut(Box::new(RefCell::new(h)))
138     }
139 }
140 
141 #[derive(Debug)]
142 /// A D-Bus Method.
143 pub struct Method<M> {
144     cb: M,
145     name: Arc<Member>,
146     i_args: Vec<Argument>,
147     o_args: Vec<Argument>,
148     anns: BTreeMap<String, String>,
149 }
150 
151 impl<M> Method<M> {
152     /// Builder method that adds an "in" Argument to this Method.
in_arg<A: Into<Argument>>(mut self, a: A) -> Self153     pub fn in_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.i_args.push(a.into()); self }
154     /// Builder method that adds multiple "in" Arguments to this Method.
in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self155     pub fn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
156         self.i_args.extend(a.into_iter().map(|b| b.into())); self
157     }
158 
159     /// Builder method that adds an "out" Argument to this Method.
out_arg<A: Into<Argument>>(mut self, a: A) -> Self160     pub fn out_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.o_args.push(a.into()); self }
161     /// Builder method that adds multiple "out" Arguments to this Method.
out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self162     pub fn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
163         self.o_args.extend(a.into_iter().map(|b| b.into())); self
164     }
165 
166     /// Add an annotation to the method.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self167     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
168         self.anns.insert(name.into(), value.into()); self
169     }
170     /// Add an annotation that this entity is deprecated.
deprecated(self) -> Self171     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
172 }
173 
174 impl<M: MethodType> Method<M> {
175     /// Call the Method.
call(&self, m: &Message, o: &ObjectPath<M>, i: &Tree<M>) -> MethodResult176     pub fn call(&self, m: &Message, o: &ObjectPath<M>, i: &Tree<M>) -> MethodResult { self.cb.call_method(m, o, i) }
177 
new(n: Member, cb: M) -> Self178     fn new(n: Member, cb: M) -> Self { Method { name: Arc::new(n), i_args: vec!(), o_args: vec!(), anns: BTreeMap::new(), cb: cb } }
179 }
180 
181 
182 #[derive(Debug)]
183 /// Represents a D-Bus interface.
184 pub struct Interface<M> {
185     name: Arc<IfaceName>,
186     methods: ArcMap<Member, Method<M>>,
187     signals: ArcMap<Member, Signal>,
188     properties: ArcMap<String, Property<M>>,
189     anns: BTreeMap<String, String>,
190 }
191 
192 impl<M> Interface<M> {
193     /// Adds a method to the interface.
add_m(mut self, m: Method<M>) -> Self194     pub fn add_m(mut self, m: Method<M>) -> Self { self.methods.insert(m.name.clone(), Arc::new(m)); self }
195     /// Adds a signal to the interface.
add_s(mut self, s: Signal) -> Self196     pub fn add_s(mut self, s: Signal) -> Self { self.signals.insert(s.name.clone(), Arc::new(s)); self }
197     /// Adds a signal to the interface. Returns a reference to the signal
198     /// (which you can use to emit the signal, once it belongs to an object path).
add_s_ref(&mut self, s: Signal) -> Arc<Signal>199     pub fn add_s_ref(&mut self, s: Signal) -> Arc<Signal> {
200         let s = Arc::new(s);
201         self.signals.insert(s.name.clone(), s.clone());
202         s
203     }
204 
205     /// Adds a property to the interface.
add_p(mut self, p: Property<M>) -> Self206     pub fn add_p(mut self, p: Property<M>) -> Self { self.properties.insert(p.name.clone(), Arc::new(p)); self }
207     /// Adds a property to the interface. Returns a reference to the property
208     /// (which you can use to get and set the current value of the property).
add_p_ref(&mut self, p: Property<M>) -> Arc<Property<M>>209     pub fn add_p_ref(&mut self, p: Property<M>) -> Arc<Property<M>> {
210         let p = Arc::new(p);
211         self.properties.insert(p.name.clone(), p.clone());
212         p
213     }
214 
215     /// Add an annotation to this Inteface.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self216     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
217         self.anns.insert(name.into(), value.into()); self
218     }
219     /// Add an annotation that this entity is deprecated.
deprecated(self) -> Self220     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
221 
new(t: IfaceName) -> Interface<M>222     fn new(t: IfaceName) -> Interface<M> {
223         Interface { name: Arc::new(t), methods: BTreeMap::new(), signals: BTreeMap::new(),
224             properties: BTreeMap::new(), anns: BTreeMap::new()
225         }
226     }
227 
228 }
229 
230 #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
231 /// Enumerates the different signaling behaviors a Property can have
232 /// to being changed.
233 pub enum EmitsChangedSignal {
234     /// The Property emits a signal that includes the new value.
235     True,
236     /// The Property emits a signal that does not include the new value.
237     Invalidates,
238     /// The Property cannot be changed.
239     Const,
240     /// The Property does not emit a signal when changed.
241     False,
242 }
243 
244 #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
245 /// The possible access characteristics a Property can have.
246 pub enum Access {
247     /// The Property can only be read (Get).
248     Read,
249     /// The Property can be read or written.
250     ReadWrite,
251     /// The Property can only be written (Set).
252     Write,
253 }
254 
255 impl Access {
introspect(&self) -> &'static str256     fn introspect(&self) -> &'static str {
257         match self {
258             &Access::Read => "read",
259             &Access::ReadWrite => "readwrite",
260             &Access::Write => "write",
261         }
262     }
263 }
264 
265 #[derive(Debug)]
266 /// A D-Bus Property.
267 pub struct Property<M> {
268     name: Arc<String>,
269     value: Mutex<MessageItem>,
270     emits: EmitsChangedSignal,
271     rw: Access,
272     set_cb: Option<M>,
273     owner: Mutex<Option<(Arc<Path>, Arc<IfaceName>)>>,
274     anns: BTreeMap<String, String>,
275 }
276 
277 impl<M: MethodType> Property<M> {
278     /// Gets the value of the Property.
get_value(&self) -> MessageItem279     pub fn get_value(&self) -> MessageItem {
280         self.value.lock().unwrap().clone()
281     }
282 
283     /// Gets the signal (if any) associated with the Property.
get_signal(&self) -> Option<Message>284     pub fn get_signal(&self) -> Option<Message> {
285         self.owner.lock().unwrap().as_ref().map(|&(ref p, ref i)| {
286             Message::signal(&p, &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
287                 .append(String::from(&***i))
288         })
289     }
290 
291     /// Returns error if "emits" is "Const", and the property is in a
292     /// tree.  Returns messages to be sent over a connection, this
293     /// could be the PropertiesChanged signal.
set_value(&self, m: MessageItem) -> Result<Vec<Message>,()>294     pub fn set_value(&self, m: MessageItem) -> Result<Vec<Message>,()> {
295         let ss = match self.emits {
296             EmitsChangedSignal::False => None,
297             EmitsChangedSignal::Const => if self.get_signal().is_some() { return Err(()) } else { None },
298             EmitsChangedSignal::True => self.get_signal().map(|mut s| {
299                 let m = MessageItem::Array(vec!(((&*self.name).clone().into(), Box::new(m.clone()).into()).into()), "{sv}".into());
300                 s.append_items(&[m]);
301                 s
302             }),
303             EmitsChangedSignal::Invalidates => self.get_signal().map(|mut s| {
304                 let m2 = [(&*self.name).clone()][..].into();
305                 s.append_items(&[MessageItem::Array(vec!(), "{sv}".into()), m2]);
306                 s
307             }),
308         };
309         *self.value.lock().unwrap() = m;
310         Ok(ss.map(|s| vec!(s)).unwrap_or(vec!()))
311     }
312 
313     /// Builder method that allows setting the Property's signal
314     /// behavior when changed.
emits_changed(mut self, e: EmitsChangedSignal) -> Self315     pub fn emits_changed(mut self, e: EmitsChangedSignal) -> Self {
316         self.emits = e;
317         assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const);
318         self
319     }
320 
321     /// Builder method that allows setting the Property as readable,
322     /// writable, or both.
access(mut self, e: Access) -> Self323     pub fn access(mut self, e: Access) -> Self {
324         self.rw = e;
325         assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const);
326         self
327     }
328 
329     /// Helper method to check accessibility before getting a value.
remote_get(&self, _: &Message) -> Result<MessageItem, MethodErr>330     pub fn remote_get(&self, _: &Message) -> Result<MessageItem, MethodErr> {
331         // TODO: We should be able to call a user-defined callback here instead...
332         if self.rw == Access::Write { return Err(MethodErr::failed(&format!("Property {} is write only", &self.name))) }
333         Ok(self.get_value())
334     }
335 
336     /// Helper method to verify and extract a MessageItem from a Set message
verify_remote_set(&self, m: &Message) -> Result<MessageItem, MethodErr>337     pub fn verify_remote_set(&self, m: &Message) -> Result<MessageItem, MethodErr> {
338         let items = m.get_items();
339         let s: &MessageItem = try!(items.get(2).ok_or_else(|| MethodErr::no_arg())
340             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
341 
342         if self.rw == Access::Read { Err(MethodErr::ro_property(&self.name)) }
343         else if s.type_sig() != self.value.lock().unwrap().type_sig() {
344             Err(MethodErr::failed(&format!("Property {} cannot change type to {}", &self.name, s.type_sig())))
345         }
346         else { Ok(s.clone()) }
347     }
348 
remote_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> Result<Vec<Message>, MethodErr>349     fn remote_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> Result<Vec<Message>, MethodErr> {
350         if let Some(ref cb) = self.set_cb {
351             cb.call_method(m, o, t)
352         }
353         else {
354             let s = try!(self.verify_remote_set(m));
355             self.set_value(s).map_err(|_| MethodErr::ro_property(&self.name))
356         }
357     }
358 
359     /// Add an annotation to this Property.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self360     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
361         self.anns.insert(name.into(), value.into()); self
362     }
363 
364     /// Add an annotation that this entity is deprecated.
deprecated(self) -> Self365     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
366 
new(s: String, i: MessageItem) -> Property<M>367     fn new(s: String, i: MessageItem) -> Property<M> {
368         Property { name: Arc::new(s), emits: EmitsChangedSignal::True, rw: Access::Read,
369             value: Mutex::new(i), owner: Mutex::new(None), anns: BTreeMap::new(), set_cb: None }
370     }
371 }
372 
373 impl Property<MethodSync> {
374     /// Sets a callback to be called when a "Set" call is coming in from the remote side.
375     /// Might change to something more ergonomic.
376     /// For multi-thread use.
on_set<H>(mut self, m: H) -> Self where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static377     pub fn on_set<H>(mut self, m: H) -> Self
378     where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static {
379         self.set_cb = Some(MethodSync::box_method(m));
380         self
381     }
382 }
383 
384 impl<'a> Property<MethodFn<'a>> {
385     /// Sets a callback to be called when a "Set" call is coming in from the remote side.
386     /// Might change to something more ergonomic.
387     /// For single-thread use.
on_set<H: 'a>(mut self, m: H) -> Self where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult388     pub fn on_set<H: 'a>(mut self, m: H) -> Self
389     where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult {
390         self.set_cb = Some(MethodFn(Box::new(m)));
391         self
392     }
393 }
394 
395 impl<'a> Property<MethodFnMut<'a>> {
396     /// Sets a callback to be called when a "Set" call is coming in from the remote side.
397     /// Might change to something more ergonomic.
398     /// For single-thread use.
on_set<H: 'a>(mut self, m: H) -> Self where H: FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult399     pub fn on_set<H: 'a>(mut self, m: H) -> Self
400     where H: FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult {
401         self.set_cb = Some(MethodFnMut(Box::new(RefCell::new(m))));
402         self
403     }
404 }
405 
406 
407 #[derive(Debug)]
408 /// A D-Bus Signal.
409 pub struct Signal {
410     name: Arc<Member>,
411     arguments: Vec<Argument>,
412     owner: Mutex<Option<(Arc<Path>, Arc<IfaceName>)>>,
413     anns: BTreeMap<String, String>,
414 }
415 
416 impl Signal {
417     /// Returns a message which emits the signal when sent.
418     /// Panics if the signal is not inserted in an object path.
emit(&self, items: &[MessageItem]) -> Message419     pub fn emit(&self, items: &[MessageItem]) -> Message {
420         let mut m = {
421             let lock = self.owner.lock().unwrap();
422             let &(ref p, ref i) = lock.as_ref().unwrap();
423             Message::signal(p, i, &self.name)
424         };
425         m.append_items(items);
426         m
427     }
428 
429     /// Builder method that adds an Argument to the Signal.
arg<A: Into<Argument>>(mut self, a: A) -> Self430     pub fn arg<A: Into<Argument>>(mut self, a: A) -> Self { self.arguments.push(a.into()); self }
431     /// Builder method that adds multiple "rguments to the Signel.
args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self432     pub fn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
433         self.arguments.extend(a.into_iter().map(|b| b.into())); self
434     }
435 
436     /// Add an annotation to this Signal.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self437     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
438         self.anns.insert(name.into(), value.into()); self
439     }
440     /// Add an annotation that this entity is deprecated.
deprecated(self) -> Self441     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
442 }
443 
introspect_anns(anns: &BTreeMap<String, String>, indent: &str) -> String444 fn introspect_anns(anns: &BTreeMap<String, String>, indent: &str) -> String {
445     anns.iter().fold("".into(), |aa, (ak, av)| {
446         format!("{}{}<annotation name=\"{}\" value=\"{}\"/>\n", aa, indent, ak, av)
447     })
448 }
449 
introspect_map<T, I: fmt::Display, C: Fn(&T) -> (String, String)> (h: &ArcMap<I, T>, name: &str, indent: &str, func: C) -> String450 fn introspect_map<T, I: fmt::Display, C: Fn(&T) -> (String, String)>
451     (h: &ArcMap<I, T>, name: &str, indent: &str, func: C) -> String {
452 
453     h.iter().fold("".into(), |a, (k, v)| {
454         let (params, contents) = func(v);
455         format!("{}{}<{} name=\"{}\"{}{}>\n",
456             a, indent, name, &**k, params, if contents.len() > 0 {
457                 format!(">\n{}{}</{}", contents, indent, name)
458             }
459             else { format!("/") }
460         )
461     })
462 }
463 
464 #[derive(Debug)]
465 /// A D-Bus Object Path.
466 pub struct ObjectPath<M> {
467     name: Arc<Path>,
468     ifaces: ArcMap<IfaceName, Interface<M>>,
469 }
470 
471 impl<M: MethodType> ObjectPath<M> {
new(p: Path) -> ObjectPath<M>472     fn new(p: Path) -> ObjectPath<M> {
473         ObjectPath { name: Arc::new(p), ifaces: BTreeMap::new() }
474     }
475 
prop_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> MethodResult476     fn prop_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> MethodResult {
477         let items = m.get_items();
478         let iface_name: &String = try!(items.get(0).ok_or_else(|| MethodErr::no_arg())
479             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
480         let prop_name: &String = try!(items.get(1).ok_or_else(|| MethodErr::no_arg())
481             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
482         let iface: &Interface<M> = try!(IfaceName::new(&**iface_name).map_err(|e| MethodErr::invalid_arg(&e))
483             .and_then(|i| self.ifaces.get(&i).ok_or_else(|| MethodErr::no_interface(&i))));
484         let prop: &Property<M> = try!(iface.properties.get(prop_name).ok_or_else(|| MethodErr::no_property(prop_name)));
485         let mut r = try!(prop.remote_set(m, o, t));
486         r.push(m.method_return());
487         Ok(r)
488     }
489 
prop_get(&self, m: &Message) -> MethodResult490     fn prop_get(&self, m: &Message) -> MethodResult {
491         let items = m.get_items();
492         let iface_name: &String = try!(items.get(0).ok_or_else(|| MethodErr::no_arg())
493             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
494         let prop_name: &String = try!(items.get(1).ok_or_else(|| MethodErr::no_arg())
495             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
496         let iface: &Interface<M> = try!(IfaceName::new(&**iface_name).map_err(|e| MethodErr::invalid_arg(&e))
497             .and_then(|i| self.ifaces.get(&i).ok_or_else(|| MethodErr::no_interface(&i))));
498         let prop: &Property<M> = try!(iface.properties.get(prop_name).ok_or_else(|| MethodErr::no_property(prop_name)));
499         let r = try!(prop.remote_get(m));
500         Ok(vec!(m.method_return().append(Box::new(r))))
501     }
502 
prop_get_all(&self, m: &Message) -> MethodResult503     fn prop_get_all(&self, m: &Message) -> MethodResult {
504         let items = m.get_items();
505         let iface_name: &String = try!(items.get(0).ok_or_else(|| MethodErr::no_arg())
506             .and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
507         let iface: &Interface<M> = try!(IfaceName::new(&**iface_name).map_err(|e| MethodErr::invalid_arg(&e))
508             .and_then(|i| self.ifaces.get(&i).ok_or_else(|| MethodErr::no_interface(&i))));
509         let mut q: Vec<MessageItem> = vec!();
510         for v in iface.properties.values() {
511              q.push(((&**v.name).into(), try!(v.remote_get(m))).into())
512         }
513         Ok(vec!(m.method_return().append(MessageItem::Array(q, "{sv}".into()))))
514     }
515 
add_property_handler(&mut self)516     fn add_property_handler(&mut self) {
517         let ifname = IfaceName::from("org.freedesktop.DBus.Properties");
518         if self.ifaces.contains_key(&ifname) { return };
519         let f: Factory<M> = Factory(PhantomData);
520         let i = Interface::<M>::new(ifname)
521             .add_m(f.method_sync("Get", |m,o,_| o.prop_get(m) )
522                 .in_arg(("interface_name", "s")).in_arg(("property_name", "s")).out_arg(("value", "v")))
523             .add_m(f.method_sync("GetAll", |m,o,_| o.prop_get_all(m))
524                 .in_arg(("interface_name", "s")).out_arg(("props", "a{sv}")))
525             .add_m(f.method_sync("Set", |m,o,t| o.prop_set(m, o, t))
526                 .in_args(vec!(("interface_name", "s"), ("property_name", "s"), ("value", "v"))));
527         self.ifaces.insert(i.name.clone(), Arc::new(i));
528     }
529 
530     /// Add an Interface to this Object Path.
add(mut self, p: Interface<M>) -> Self531     pub fn add(mut self, p: Interface<M>) -> Self {
532         for s in p.signals.values() {
533             *s.owner.lock().unwrap() = Some((self.name.clone(), p.name.clone()))
534         };
535         for s in p.properties.values() {
536             *s.owner.lock().unwrap() = Some((self.name.clone(), p.name.clone()))
537         };
538         if !p.properties.is_empty() { self.add_property_handler(); }
539         self.ifaces.insert(p.name.clone(), Arc::new(p));
540         self
541     }
542 
543     /// Adds introspection support for this object path.
introspectable(self) -> Self544     pub fn introspectable(self) -> Self {
545         let ifname: IfaceName = "org.freedesktop.DBus.Introspectable".into();
546         if self.ifaces.contains_key(&ifname) { return self };
547         let f: Factory<M> = Factory(PhantomData);
548         self.add(Interface::<M>::new(ifname)
549             .add_m(f.method_sync("Introspect",
550                 |m,o,t| Ok(vec!(m.method_return().append(o.introspect(t)))))
551                 .out_arg(("xml_data", "s"))))
552     }
553 
handle(&self, m: &Message, t: &Tree<M>) -> MethodResult554     fn handle(&self, m: &Message, t: &Tree<M>) -> MethodResult {
555         let i = try!(m.interface().and_then(|i| self.ifaces.get(&i)).ok_or(
556             ("org.freedesktop.DBus.Error.UnknownInterface", "Unknown interface")));
557         let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or(
558             ("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")));
559         me.call(m, &self, t)
560     }
561 
introspect(&self, tree: &Tree<M>) -> String562     fn introspect(&self, tree: &Tree<M>) -> String {
563         let ifacestr = introspect_map(&self.ifaces, "interface", "  ", |iv|
564             (format!(""), format!("{}{}{}{}",
565                 introspect_map(&iv.methods, "method", "    ", |m| (format!(""), format!("{}{}{}",
566                     Argument::introspect_all(&m.i_args, "      ", " direction=\"in\""),
567                     Argument::introspect_all(&m.o_args, "      ", " direction=\"out\""),
568                     introspect_anns(&m.anns, "      ")
569                 ))),
570                 introspect_map(&iv.properties, "property", "    ", |p| (
571                     format!(" type=\"{}\" access=\"{}\"", p.get_value().type_sig(), p.rw.introspect()),
572                     introspect_anns(&p.anns, "      ")
573                 )),
574                 introspect_map(&iv.signals, "signal", "    ", |s| (format!(""), format!("{}{}",
575                     Argument::introspect_all(&s.arguments, "      ", ""),
576                     introspect_anns(&s.anns, "      ")
577                 ))),
578                 introspect_anns(&iv.anns, "    ")
579             ))
580         );
581         let olen = self.name.len()+1;
582         let childstr = tree.children(&self, true).iter().fold("".to_string(), |na, n|
583             format!("{}  <node name=\"{}\"/>\n", na, &n.name[olen..])
584         );
585 
586         let nodestr = format!(r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
587 <node name="{}">
588 {}{}</node>"##, self.name, ifacestr, childstr);
589         nodestr
590     }
591 
get_managed_objects(&self, t: &Tree<M>) -> MessageItem592     fn get_managed_objects(&self, t: &Tree<M>) -> MessageItem {
593         let mut paths = t.children(&self, false);
594         paths.push(&self);
595         MessageItem::Array(
596             paths.iter().map(|p| ((&*p.name).clone().into(), MessageItem::Array(
597                 p.ifaces.values().map(|i| ((&**i.name).into(), MessageItem::Array(
598                     i.properties.values().map(|pp| ((&**pp.name).into(), Box::new(pp.get_value()
599                     ).into()).into()).collect(), "{sv}".into()
600                 )).into()).collect(), "{sa{sv}}".into()
601             )).into()).collect(), "{oa{sa{sv}}}".into()
602         )
603     }
604 
605     /// Adds ObjectManager support for this object path.
606     ///
607     /// It is not possible to add/remove interfaces while the object path belongs to a tree,
608     /// hence no InterfacesAdded / InterfacesRemoved signals are sent.
object_manager(self) -> Self609     pub fn object_manager(self) -> Self {
610         let ifname: IfaceName = "org.freedesktop.DBus.ObjectManager".into();
611         if self.ifaces.contains_key(&ifname) { return self };
612         let f: Factory<M> = Factory(PhantomData);
613         self.add(Interface::<M>::new(ifname)
614             .add_m(f.method_sync("GetManagedObjects",
615                 |m,o,t| Ok(vec!(m.method_return().append(o.get_managed_objects(t)))))
616                 .out_arg("a{oa{sa{sv}}}")))
617     }
618 }
619 
620 /// An iterator adapter that handles incoming method calls.
621 ///
622 /// Method calls that match an object path in the tree are handled and consumed by this
623 /// iterator. Other messages are passed through.
624 pub struct TreeServer<'a, I, M: 'a> {
625     iter: I,
626     conn: &'a Connection,
627     tree: &'a Tree<M>,
628 }
629 
630 impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType> Iterator for TreeServer<'a, I, M> {
631     type Item = ConnectionItem;
632 
next(&mut self) -> Option<ConnectionItem>633     fn next(&mut self) -> Option<ConnectionItem> {
634         loop {
635             let n = self.iter.next();
636             if let &Some(ConnectionItem::MethodCall(ref msg)) = &n {
637                 if let Some(v) = self.tree.handle(&msg) {
638                     // Probably the wisest is to ignore any send errors here -
639                     // maybe the remote has disconnected during our processing.
640                     for m in v { let _ = self.conn.send(m); };
641                     continue;
642                 }
643             }
644             return n;
645         }
646     }
647 }
648 
649 /// A collection of object paths.
650 #[derive(Debug)]
651 pub struct Tree<M> {
652     paths: ArcMap<Path, ObjectPath<M>>
653 }
654 
655 impl<M: MethodType> Tree<M> {
656 
children(&self, o: &ObjectPath<M>, direct_only: bool) -> Vec<&ObjectPath<M>>657     fn children(&self, o: &ObjectPath<M>, direct_only: bool) -> Vec<&ObjectPath<M>> {
658         let parent: &str = &o.name;
659         let plen = parent.len()+1;
660         self.paths.values().filter_map(|v| {
661             let k: &str = &v.name;
662             if !k.starts_with(parent) || k.len() <= plen || &k[plen-1..plen] != "/" {None} else {
663                 let child = &k[plen..];
664                 if direct_only && child.contains("/") {None} else {Some(&**v)}
665             }
666         }).collect()
667     }
668 
669     /// Add a Object Path to this Tree.
add(mut self, p: ObjectPath<M>) -> Self670     pub fn add(mut self, p: ObjectPath<M>) -> Self {
671         self.paths.insert(p.name.clone(), Arc::new(p));
672         self
673     }
674 
675     /// Registers or unregisters all object paths in the tree.
set_registered(&self, c: &Connection, b: bool) -> Result<(), Error>676     pub fn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> {
677         let mut regd_paths = Vec::new();
678         for p in self.paths.keys() {
679             if b {
680                 match c.register_object_path(p) {
681                     Ok(()) => regd_paths.push(p.clone()),
682                     Err(e) => {
683                         while let Some(rp) = regd_paths.pop() {
684                             c.unregister_object_path(&rp);
685                         }
686                         return Err(e)
687                     }
688                 }
689             } else {
690                 c.unregister_object_path(p);
691             }
692         }
693         Ok(())
694     }
695 
696     /// Handles a message. Will return None in case the object path was not
697     /// found, or otherwise a list of messages to be sent back.
handle(&self, m: &Message) -> Option<Vec<Message>>698     pub fn handle(&self, m: &Message) -> Option<Vec<Message>> {
699         if m.msg_type() != MessageType::MethodCall { None }
700         else { m.path().and_then(|p| self.paths.get(&p).map(|s| s.handle(m, &self)
701             .unwrap_or_else(|e| vec!(m.error(&e.0, &CString::new(e.1).unwrap()))))) }
702     }
703 
704     /// This method takes an `ConnectionItem` iterator (you get it from `Connection::iter()`)
705     /// and handles all matching items. Non-matching items (e g signals) are passed through.
run<'a, I: Iterator<Item=ConnectionItem>>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M>706     pub fn run<'a, I: Iterator<Item=ConnectionItem>>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M> {
707         TreeServer { iter: i, tree: &self, conn: c }
708     }
709 }
710 
711 /// The factory is used to create object paths, interfaces, methods etc.
712 ///
713 /// There are three factories:
714 ///
715 ///  **Fn** - all methods are `Fn()`.
716 ///
717 ///  **FnMut** - all methods are `FnMut()`. This means they can mutate their environment,
718 ///  which has the side effect that if you call it recursively, it will RefCell panic.
719 ///
720 ///  **Sync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods
721 ///  can be called from different threads in parallel.
722 #[derive(Debug, Copy, Clone)]
723 pub struct Factory<M>(PhantomData<M>);
724 
725 impl<'a> Factory<MethodFn<'a>> {
726 
727     /// Creates a new factory for single-thread use.
new_fn() -> Self728     pub fn new_fn() -> Self { Factory(PhantomData) }
729 
730     /// Creates a new method for single-thread use.
method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFn<'b>> where H: Fn(&Message, &ObjectPath<MethodFn<'b>>, &Tree<MethodFn<'b>>) -> MethodResult, T: Into<Member>731     pub fn method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFn<'b>>
732     where H: Fn(&Message, &ObjectPath<MethodFn<'b>>, &Tree<MethodFn<'b>>) -> MethodResult, T: Into<Member> {
733         Method::new(t.into(), MethodFn(Box::new(handler)))
734     }
735 
736     /// Creates a new property for single-thread use.
property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFn<'b>>737     pub fn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFn<'b>> {
738         Property::new(t.into(), i.into())
739     }
740 
741     /// Creates a new interface for single-thread use.
interface<'b, T: Into<IfaceName>>(&self, t: T) -> Interface<MethodFn<'b>>742     pub fn interface<'b, T: Into<IfaceName>>(&self, t: T) -> Interface<MethodFn<'b>> { Interface::new(t.into()) }
743 
744     /// Creates a new tree for single-thread use.
tree<'b>(&self) -> Tree<MethodFn<'b>>745     pub fn tree<'b>(&self) -> Tree<MethodFn<'b>> { Tree { paths: BTreeMap::new() }}
746 
747     /// Creates a new object path for single-thread use.
object_path<'b, T: Into<Path>>(&self, t: T) -> ObjectPath<MethodFn<'b>>748     pub fn object_path<'b, T: Into<Path>>(&self, t: T) -> ObjectPath<MethodFn<'b>> { ObjectPath::new(t.into()) }
749 }
750 
751 impl<'a> Factory<MethodFnMut<'a>> {
752 
753     /// Creates a new factory for single-thread + mutable fns use.
new_fnmut() -> Self754     pub fn new_fnmut() -> Self { Factory(PhantomData) }
755 
756     /// Creates a new method for single-thread use.
757     /// This method can mutate its environment, so it will panic in case
758     /// it is called recursively.
method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFnMut<'b>> where H: FnMut(&Message, &ObjectPath<MethodFnMut<'b>>, &Tree<MethodFnMut<'b>>) -> MethodResult, T: Into<Member>759     pub fn method<'b, H: 'b, T>(&self, t: T, handler: H) -> Method<MethodFnMut<'b>>
760     where H: FnMut(&Message, &ObjectPath<MethodFnMut<'b>>, &Tree<MethodFnMut<'b>>) -> MethodResult, T: Into<Member> {
761         Method::new(t.into(), MethodFnMut(Box::new(RefCell::new(handler))))
762     }
763 
764     /// Creates a new mutable property for single-thread use.
property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFnMut<'b>>765     pub fn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFnMut<'b>> {
766         Property::new(t.into(), i.into())
767     }
768 
769     /// Creates a new mutable interface for single-thread use.
interface<'b, T: Into<IfaceName>>(&self, t: T) -> Interface<MethodFnMut<'b>>770     pub fn interface<'b, T: Into<IfaceName>>(&self, t: T) -> Interface<MethodFnMut<'b>> { Interface::new(t.into()) }
771 
772     /// Creates a new mutable tree for single-thread use.
tree<'b>(&self) -> Tree<MethodFnMut<'b>>773     pub fn tree<'b>(&self) -> Tree<MethodFnMut<'b>> { Tree { paths: BTreeMap::new() }}
774 
775     /// Creates a new mutable object path for single-thread use.
object_path<'b, T: Into<Path>>(&self, t: T) -> ObjectPath<MethodFnMut<'b>>776     pub fn object_path<'b, T: Into<Path>>(&self, t: T) -> ObjectPath<MethodFnMut<'b>> { ObjectPath::new(t.into()) }
777 }
778 
779 impl Factory<MethodSync> {
780 
781     /// Creates a new factory for multi-thread use.
782     /// Trees created will be able to Send and Sync, i e,
783     /// it can handle several messages in parallel.
new_sync() -> Self784     pub fn new_sync() -> Self { Factory(PhantomData) }
785 
786     /// Creates a new method for multi-thread use.
787     /// This puts bounds on the callback to enable it to be called from several threads
788     /// in parallel.
method<H, T>(&self, t: T, handler: H) -> Method<MethodSync> where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static, T: Into<Member>789     pub fn method<H, T>(&self, t: T, handler: H) -> Method<MethodSync>
790     where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static, T: Into<Member> {
791         Method::new(t.into(), MethodSync(Box::new(handler)))
792     }
793 
794     /// Creates a new property for multi-threaded use.
property<T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodSync>795     pub fn property<T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodSync> {
796         Property::new(t.into(), i.into())
797     }
798 
799     /// Creates a new interface for multi-threaded use.
interface<T: Into<IfaceName>>(&self, t: T) -> Interface<MethodSync>800     pub fn interface<T: Into<IfaceName>>(&self, t: T) -> Interface<MethodSync> { Interface::new(t.into()) }
801 
802     /// Creates a new tree for multi-threaded use.
tree(&self) -> Tree<MethodSync>803     pub fn tree(&self) -> Tree<MethodSync> { Tree { paths: BTreeMap::new() }}
804 
805     /// Creates a new object path for multi-threaded use.
object_path<T: Into<Path>>(&self, t: T) -> ObjectPath<MethodSync>806     pub fn object_path<T: Into<Path>>(&self, t: T) -> ObjectPath<MethodSync> { ObjectPath::new(t.into()) }
807 }
808 
809 impl<M> Factory<M> {
810     /// Create a Signal.
signal<T: Into<Member>>(&self, t: T) -> Signal811     pub fn signal<T: Into<Member>>(&self, t: T) -> Signal {
812         Signal { name: Arc::new(t.into()), arguments: vec!(), owner: Mutex::new(None), anns: BTreeMap::new() }
813     }
814 }
815 
816 impl<M: MethodType> Factory<M> {
817     /// Creates a new method with bounds enough to be used in all trees.
method_sync<H, T>(&self, t: T, handler: H) -> Method<M> where H: Fn(&Message, &ObjectPath<M>, &Tree<M>) -> MethodResult + Send + Sync + 'static, T: Into<Member>818     pub fn method_sync<H, T>(&self, t: T, handler: H) -> Method<M>
819     where H: Fn(&Message, &ObjectPath<M>, &Tree<M>) -> MethodResult + Send + Sync + 'static, T: Into<Member> {
820         Method::new(t.into(), M::box_method(handler))
821     }
822 }
823 
824 #[test]
factory_test()825 fn factory_test() {
826     let f = Factory::new_fn();
827     f.interface("com.example.hello").deprecated();
828     let b = 5i32;
829     f.method("GetSomething", |m,_,_| Ok(vec!({ let mut z = m.method_return(); z.append_items(&[b.into()]); z})));
830     let t = f.tree().add(f.object_path("/funghi").add(f.interface("a.b.c").deprecated()));
831     let t = t.add(f.object_path("/ab")).add(f.object_path("/a")).add(f.object_path("/a/b/c")).add(f.object_path("/a/b"));
832     assert_eq!(t.children(t.paths.get(&Path::from("/a")).unwrap(), true).len(), 1);
833 }
834 
835 #[test]
test_sync_prop()836 fn test_sync_prop() {
837     let f = Factory::new_sync();
838     let mut i = f.interface("com.example.echo");
839     let p = i.add_p_ref(f.property("EchoCount", 7i32));
840     let tree1 = Arc::new(f.tree().add(f.object_path("/echo").introspectable().add(i)));
841     let tree2 = tree1.clone();
842     println!("{:#?}", tree2);
843     ::std::thread::spawn(move || {
844         let r = p.set_value(9i32.into()).unwrap();
845         let signal = r.get(0).unwrap();
846         assert_eq!(signal.msg_type(), MessageType::Signal);
847         let mut msg = Message::new_method_call("com.example.echoserver", "/echo", "com.example", "dummy").unwrap();
848         super::message::message_set_serial(&mut msg, 3);
849         tree2.handle(&msg);
850     });
851 
852     let mut msg = Message::new_method_call("com.example.echoserver", "/echo", "org.freedesktop.DBus.Properties", "Get").unwrap()
853         .append("com.example.echo").append("EchoCount");
854     super::message::message_set_serial(&mut msg, 4);
855     let r = tree1.handle(&msg).unwrap();
856     let r1 = r.get(0).unwrap();
857     let ii = r1.get_items();
858     let vv: &MessageItem = ii.get(0).unwrap().inner().unwrap();
859     let v: i32 = vv.inner().unwrap();
860     assert!(v == 7 || v == 9);
861 }
862 
863 /* This test case no longer works, for unknown reason, see
864    https://github.com/diwic/dbus-rs/issues/27
865 #[test]
866 fn prop_lifetime_simple() {
867     let f = Factory::new_fnmut();
868     let count;
869     let mut i = f.interface("com.example.dbus.rs");
870     count = i.add_p_ref(f.property("changes", 0i32));
871 
872     let _setme = i.add_p_ref(f.property("setme", 0u8).access(Access::ReadWrite).on_set(|_,_,_| {
873         let v: i32 = count.get_value().inner().unwrap();
874         count.set_value((v + 1).into()).unwrap();
875         Ok(vec!())
876     }));
877 }
878 */
879 
880 /* This test case no longer works, for unknown reason, see
881    https://github.com/diwic/dbus-rs/issues/27
882 #[test]
883 fn prop_server() {
884     let (count, setme): (_, RefCell<Option<Arc<Property<_>>>>);
885     setme = RefCell::new(None);
886     let f = Factory::new_fnmut();
887     let mut i = f.interface("com.example.dbus.rs");
888     count = i.add_p_ref(f.property("changes", 0i32));
889     *setme.borrow_mut() = Some(i.add_p_ref(f.property("setme", 0u8).access(Access::ReadWrite).on_set(|m,_,_| {
890         let ss2 = setme.borrow();
891         let ss = ss2.as_ref().unwrap();
892         let s = try!(ss.verify_remote_set(m));
893         let r = try!(ss.set_value(s).map_err(|_| MethodErr::ro_property(&ss.name)));
894         let v: i32 = count.get_value().inner().unwrap();
895         count.set_value((v + 1).into()).unwrap();
896         Ok(r)
897     })));
898     let tree = f.tree().add(f.object_path("/example").add(i));
899 
900     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Get").unwrap()
901         .append("com.example.dbus.rs").append("changes");
902     super::message::message_set_serial(&mut msg, 10);
903     let r = tree.handle(&msg).unwrap();
904     let r1 = r.get(0).unwrap();
905     let ii = r1.get_items();
906     let vv: &MessageItem = ii.get(0).unwrap().inner().unwrap();
907     let v: i32 = vv.inner().unwrap();
908     assert_eq!(v, 0);
909 
910     // Read-only
911     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
912         .append("com.example.dbus.rs").append("changes").append(5i32);
913     super::message::message_set_serial(&mut msg, 20);
914     let mut r = tree.handle(&msg).unwrap();
915     assert!(r.get_mut(0).unwrap().as_result().is_err());
916 
917     // Wrong type
918     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
919         .append("com.example.dbus.rs").append("setme").append(8i32);
920     super::message::message_set_serial(&mut msg, 30);
921     let mut r = tree.handle(&msg).unwrap();
922     assert!(r.get_mut(0).unwrap().as_result().is_err());
923 
924     // Correct!
925     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
926         .append("com.example.dbus.rs").append("setme").append(Box::new(9u8.into()));
927     super::message::message_set_serial(&mut msg, 30);
928     let mut r = tree.handle(&msg).unwrap();
929 
930     println!("{:?}", r[0].as_result());
931 
932     let c: i32 = count.get_value().inner().unwrap();
933     assert_eq!(c, 1);
934 
935 }
936 */
937 
938 #[test]
test_introspection()939 fn test_introspection() {
940     let f = Factory::new_sync();
941     let t = f.object_path("/echo").introspectable()
942         .add(f.interface("com.example.echo")
943             .add_m(f.method("Echo", |_,_,_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
944             .add_p(f.property("EchoCount", 7i32))
945             .add_s(f.signal("Echoed").arg(("data", "s")))
946     );
947 
948     let actual_result = t.introspect(&f.tree().add(f.object_path("/echo/subpath")));
949     println!("\n=== Introspection XML start ===\n{}\n=== Introspection XML end ===", actual_result);
950 
951     let expected_result = r##"<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
952 <node name="/echo">
953   <interface name="com.example.echo">
954     <method name="Echo">
955       <arg name="request" type="s" direction="in"/>
956       <arg name="reply" type="s" direction="out"/>
957     </method>
958     <property name="EchoCount" type="i" access="read"/>
959     <signal name="Echoed">
960       <arg name="data" type="s"/>
961     </signal>
962   </interface>
963   <interface name="org.freedesktop.DBus.Introspectable">
964     <method name="Introspect">
965       <arg name="xml_data" type="s" direction="out"/>
966     </method>
967   </interface>
968   <interface name="org.freedesktop.DBus.Properties">
969     <method name="Get">
970       <arg name="interface_name" type="s" direction="in"/>
971       <arg name="property_name" type="s" direction="in"/>
972       <arg name="value" type="v" direction="out"/>
973     </method>
974     <method name="GetAll">
975       <arg name="interface_name" type="s" direction="in"/>
976       <arg name="props" type="a{sv}" direction="out"/>
977     </method>
978     <method name="Set">
979       <arg name="interface_name" type="s" direction="in"/>
980       <arg name="property_name" type="s" direction="in"/>
981       <arg name="value" type="v" direction="in"/>
982     </method>
983   </interface>
984   <node name="subpath"/>
985 </node>"##;
986 
987     assert_eq!(expected_result, actual_result);
988 }
989 
990