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