1 use super::utils::{ArcMap, Iter, IterE, Annotations, Introspect};
2 use super::{Factory, MethodType, MethodInfo, MethodResult, MethodErr, DataType, Property, Method, Signal, methodtype};
3 use std::sync::{Arc, Mutex};
4 use {Member, Message, Path, Signature, MessageType, Connection, ConnectionItem, Error, arg, MsgHandler, MsgHandlerType, MsgHandlerResult};
5 use Interface as IfaceName;
6 use std::fmt;
7 use std::ffi::CStr;
8 use super::leaves::prop_append_dict;
9
introspect_map<I: fmt::Display, T: Introspect> (h: &ArcMap<I, T>, indent: &str) -> String10 fn introspect_map<I: fmt::Display, T: Introspect>
11 (h: &ArcMap<I, T>, indent: &str) -> String {
12
13 h.iter().fold("".into(), |a, (k, v)| {
14 let (name, params, contents) = (v.xml_name(), v.xml_params(), v.xml_contents());
15 format!("{}{}<{} name=\"{}\"{}{}>\n",
16 a, indent, name, &*k, params, if contents.len() > 0 {
17 format!(">\n{}{}</{}", contents, indent, name)
18 }
19 else { format!("/") }
20 )
21 })
22 }
23
24 #[derive(Debug)]
25 /// Represents a D-Bus interface.
26 pub struct Interface<M: MethodType<D>, D: DataType> {
27 name: Arc<IfaceName<'static>>,
28 methods: ArcMap<Member<'static>, Method<M, D>>,
29 signals: ArcMap<Member<'static>, Signal<D>>,
30 properties: ArcMap<String, Property<M, D>>,
31 anns: Annotations,
32 data: D::Interface,
33 }
34
35 impl<M: MethodType<D>, D: DataType> Interface<M, D> {
36 /// Builder function that adds a method to the interface.
add_m<I: Into<Arc<Method<M, D>>>>(mut self, m: I) -> Self37 pub fn add_m<I: Into<Arc<Method<M, D>>>>(mut self, m: I) -> Self {
38 let m = m.into();
39 self.methods.insert(m.get_name().clone(), m);
40 self
41 }
42
43 /// Builder function that adds a signal to the interface.
add_s<I: Into<Arc<Signal<D>>>>(mut self, s: I) -> Self44 pub fn add_s<I: Into<Arc<Signal<D>>>>(mut self, s: I) -> Self {
45 let m = s.into();
46 self.signals.insert(m.get_name().clone(), m);
47 self
48 }
49
50 /// Builder function that adds a property to the interface.
add_p<I: Into<Arc<Property<M, D>>>>(mut self, p: I) -> Self51 pub fn add_p<I: Into<Arc<Property<M, D>>>>(mut self, p: I) -> Self {
52 let m = p.into();
53 self.properties.insert(m.get_name().to_owned(), m);
54 self
55 }
56
57 /// Builder function that adds an annotation to this interface.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self58 pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
59 self.anns.insert(name, value); self
60 }
61
62 /// Builder function that adds an annotation that this entity is deprecated.
deprecated(self) -> Self63 pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
64
65 /// Get interface name
get_name(&self) -> &IfaceName<'static>66 pub fn get_name(&self) -> &IfaceName<'static> { &self.name }
67
68 /// Get associated data
get_data(&self) -> &D::Interface69 pub fn get_data(&self) -> &D::Interface { &self.data }
70
71 /// Iterates over methods implemented by this interface.
iter_m<'a>(&'a self) -> Iter<'a, Method<M, D>>72 pub fn iter_m<'a>(&'a self) -> Iter<'a, Method<M, D>> { IterE::Member(self.methods.values()).into() }
73
74 /// Iterates over signals implemented by this interface.
iter_s<'a>(&'a self) -> Iter<'a, Signal<D>>75 pub fn iter_s<'a>(&'a self) -> Iter<'a, Signal<D>> { IterE::Member(self.signals.values()).into() }
76
77 /// Iterates over properties implemented by this interface.
iter_p<'a>(&'a self) -> Iter<'a, Property<M, D>>78 pub fn iter_p<'a>(&'a self) -> Iter<'a, Property<M, D>> { IterE::String(self.properties.values()).into() }
79 }
80
81 impl<M: MethodType<D>, D: DataType> Introspect for Interface<M, D> {
xml_name(&self) -> &'static str82 fn xml_name(&self) -> &'static str { "interface" }
xml_params(&self) -> String83 fn xml_params(&self) -> String { String::new() }
xml_contents(&self) -> String84 fn xml_contents(&self) -> String {
85 format!("{}{}{}{}",
86 introspect_map(&self.methods, " "),
87 introspect_map(&self.properties, " "),
88 introspect_map(&self.signals, " "),
89 self.anns.introspect(" "))
90 }
91 }
92
93
new_interface<M: MethodType<D>, D: DataType>(t: IfaceName<'static>, d: D::Interface) -> Interface<M, D>94 pub fn new_interface<M: MethodType<D>, D: DataType>(t: IfaceName<'static>, d: D::Interface) -> Interface<M, D> {
95 Interface { name: Arc::new(t), methods: ArcMap::new(), signals: ArcMap::new(),
96 properties: ArcMap::new(), anns: Annotations::new(), data: d
97 }
98 }
99
100
101 #[derive(Debug)]
102 /// Cache of built-in interfaces, in order to save memory when many object paths implement the same interface(s).
103 pub struct IfaceCache<M: MethodType<D>, D: DataType>(Mutex<ArcMap<IfaceName<'static>, Interface<M, D>>>);
104
105 impl<M: MethodType<D>, D: DataType> IfaceCache<M, D>
106 where D::Interface: Default {
get<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>> where F: FnOnce(Interface<M, D>) -> Interface<M, D>107 pub fn get<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>>
108 where F: FnOnce(Interface<M, D>) -> Interface<M, D> {
109 let s2 = s.clone().into();
110 let mut m = self.0.lock().unwrap();
111 m.entry(s2).or_insert_with(|| {
112 let i = new_interface(s.into(), Default::default());
113 Arc::new(f(i))
114 }).clone()
115 }
116 }
117
118 impl<M: MethodType<D>, D: DataType> IfaceCache<M, D> {
get_factory<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>> where F: FnOnce() -> Interface<M, D>119 pub fn get_factory<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>>
120 where F: FnOnce() -> Interface<M, D> {
121 let s2 = s.clone().into();
122 let mut m = self.0.lock().unwrap();
123 m.entry(s2).or_insert_with(|| {
124 Arc::new(f())
125 }).clone()
126 }
127
128
new() -> Arc<Self>129 pub fn new() -> Arc<Self> { Arc::new(IfaceCache(Mutex::new(ArcMap::new()))) }
130 }
131
132 #[derive(Debug)]
133 /// A D-Bus Object Path.
134 pub struct ObjectPath<M: MethodType<D>, D: DataType> {
135 name: Arc<Path<'static>>,
136 default_iface: Option<IfaceName<'static>>,
137 ifaces: ArcMap<Arc<IfaceName<'static>>, Interface<M, D>>,
138 ifacecache: Arc<IfaceCache<M, D>>,
139 data: D::ObjectPath,
140 }
141
142 impl<M: MethodType<D>, D: DataType> ObjectPath<M, D> {
143
144 /// Get property name
get_name(&self) -> &Path<'static>145 pub fn get_name(&self) -> &Path<'static> { &self.name }
146
147 /// Get associated data
get_data(&self) -> &D::ObjectPath148 pub fn get_data(&self) -> &D::ObjectPath { &self.data }
149
150 /// Iterates over interfaces implemented by this object path.
iter<'a>(&'a self) -> Iter<'a, Interface<M, D>>151 pub fn iter<'a>(&'a self) -> Iter<'a, Interface<M, D>> { IterE::Iface(self.ifaces.values()).into() }
152
introspect(&self, tree: &Tree<M, D>) -> String153 pub(super) fn introspect(&self, tree: &Tree<M, D>) -> String {
154 let ifacestr = introspect_map(&self.ifaces, " ");
155 let olen = self.name.len()+1;
156 let childstr = tree.children(self, true).iter().fold("".to_string(), |na, n|
157 format!("{} <node name=\"{}\"/>\n", na, &n.name[olen..])
158 );
159
160 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">
161 <node name="{}">
162 {}{}</node>"##, self.name, ifacestr, childstr);
163 nodestr
164 }
165
get_iface<'a>(&'a self, iface_name: &'a CStr) -> Result<&Arc<Interface<M, D>>, MethodErr>166 fn get_iface<'a>(&'a self, iface_name: &'a CStr) -> Result<&Arc<Interface<M, D>>, MethodErr> {
167 let j = try!(IfaceName::from_slice(iface_name.to_bytes_with_nul()).map_err(|e| MethodErr::invalid_arg(&e)));
168 self.ifaces.get(&j).ok_or_else(|| MethodErr::no_interface(&j))
169 }
170
prop_get(&self, m: &MethodInfo<M, D>) -> MethodResult171 fn prop_get(&self, m: &MethodInfo<M, D>) -> MethodResult {
172 let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
173 let iface = try!(self.get_iface(iname));
174 let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
175 .ok_or_else(|| MethodErr::no_property(&prop_name)));
176 try!(prop.can_get());
177 let mut mret = m.msg.method_return();
178 {
179 let mut iter = arg::IterAppend::new(&mut mret);
180 let pinfo = m.to_prop_info(iface, prop);
181 try!(prop.get_as_variant(&mut iter, &pinfo));
182 }
183 Ok(vec!(mret))
184 }
185
prop_get_all(&self, m: &MethodInfo<M, D>) -> MethodResult186 fn prop_get_all(&self, m: &MethodInfo<M, D>) -> MethodResult {
187 let iface = try!(self.get_iface(try!(m.msg.read1())));
188 let mut mret = m.msg.method_return();
189 try!(prop_append_dict(&mut arg::IterAppend::new(&mut mret),
190 iface.properties.values().map(|v| &**v), m));
191 Ok(vec!(mret))
192 }
193
194
prop_set(&self, m: &MethodInfo<M, D>) -> MethodResult195 fn prop_set(&self, m: &MethodInfo<M, D>) -> MethodResult {
196 let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
197 let iface = try!(self.get_iface(iname));
198 let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
199 .ok_or_else(|| MethodErr::no_property(&prop_name)));
200
201 let mut iter = arg::Iter::new(m.msg);
202 iter.next(); iter.next();
203 let mut iter2 = iter;
204 try!(prop.can_set(Some(iter)));
205
206 let pinfo = m.to_prop_info(iface, prop);
207 let mut r: Vec<Message> = try!(prop.set_as_variant(&mut iter2, &pinfo)).into_iter().collect();
208 r.push(m.msg.method_return());
209 Ok(r)
210
211 }
212
get_managed_objects(&self, m: &MethodInfo<M, D>) -> MethodResult213 fn get_managed_objects(&self, m: &MethodInfo<M, D>) -> MethodResult {
214 use arg::{Dict, Variant};
215 let mut paths = m.tree.children(&self, false);
216 paths.push(&self);
217 let mut result = Ok(());
218 let mut r = m.msg.method_return();
219 {
220 let mut i = arg::IterAppend::new(&mut r);
221 i.append_dict(&Signature::make::<Path>(), &Signature::make::<Dict<&str,Dict<&str,Variant<()>,()>,()>>(), |ii| {
222 for p in paths {
223 ii.append_dict_entry(|pi| {
224 pi.append(&*p.name);
225 pi.append_dict(&Signature::make::<&str>(), &Signature::make::<Dict<&str,Variant<()>,()>>(), |pii| {
226 for ifaces in p.ifaces.values() {
227 let m2 = MethodInfo { msg: m.msg, path: p, iface: ifaces, tree: m.tree, method: m.method };
228 pii.append_dict_entry(|ppii| {
229 ppii.append(&**ifaces.name);
230 result = prop_append_dict(ppii, ifaces.properties.values().map(|v| &**v), &m2);
231 });
232 if result.is_err() { break; }
233 }
234 });
235 });
236 if result.is_err() { break; }
237 }
238 });
239 }
240 try!(result);
241 Ok(vec!(r))
242 }
243
handle(&self, m: &Message, t: &Tree<M, D>) -> MethodResult244 fn handle(&self, m: &Message, t: &Tree<M, D>) -> MethodResult {
245 let iname = m.interface().or_else(|| { self.default_iface.clone() });
246 let i = try!(iname.and_then(|i| self.ifaces.get(&i)).ok_or_else(|| MethodErr::no_interface(&"")));
247 let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or_else(|| MethodErr::no_method(&"")));
248 let minfo = MethodInfo { msg: m, tree: t, path: self, iface: i, method: me };
249 me.call(&minfo)
250 }
251
252 }
253
254 impl<M: MethodType<D>, D: DataType> ObjectPath<M, D>
255 where <D as DataType>::Interface: Default, <D as DataType>::Method: Default
256 {
257 /// Adds introspection support for this object path.
introspectable(self) -> Self258 pub fn introspectable(self) -> Self {
259 let z = self.ifacecache.get_factory("org.freedesktop.DBus.Introspectable", || {
260 let f = Factory::from(self.ifacecache.clone());
261 methodtype::org_freedesktop_dbus_introspectable_server(&f, Default::default())
262 });
263 self.add(z)
264 }
265
266 /// Builder function that adds a interface to the object path.
add<I: Into<Arc<Interface<M, D>>>>(mut self, s: I) -> Self267 pub fn add<I: Into<Arc<Interface<M, D>>>>(mut self, s: I) -> Self {
268 let m = s.into();
269 if !m.properties.is_empty() { self.add_property_handler(); }
270 self.ifaces.insert(m.name.clone(), m);
271 self
272 }
273
274 /// Builder function that sets what interface should be dispatched on an incoming
275 /// method call without interface.
default_interface(mut self, i: IfaceName<'static>) -> Self276 pub fn default_interface(mut self, i: IfaceName<'static>) -> Self {
277 self.default_iface = Some(i);
278 self
279 }
280
281 /// Adds ObjectManager support for this object path.
282 ///
283 /// It is not possible to add/remove interfaces while the object path belongs to a tree,
284 /// hence no InterfacesAdded / InterfacesRemoved signals are sent.
object_manager(mut self) -> Self285 pub fn object_manager(mut self) -> Self {
286 use arg::{Variant, Dict};
287 let ifname = IfaceName::from("org.freedesktop.DBus.ObjectManager");
288 if self.ifaces.contains_key(&ifname) { return self };
289 let z = self.ifacecache.get(ifname, |i| {
290 i.add_m(super::leaves::new_method("GetManagedObjects".into(), Default::default(),
291 M::make_method(|m| m.path.get_managed_objects(m)))
292 .outarg::<Dict<Path,Dict<&str,Dict<&str,Variant<()>,()>,()>,()>,_>("objpath_interfaces_and_properties"))
293 });
294 self.ifaces.insert(z.name.clone(), z);
295 self
296 }
297
add_property_handler(&mut self)298 fn add_property_handler(&mut self) {
299 use arg::{Variant, Dict};
300 let ifname = IfaceName::from("org.freedesktop.DBus.Properties");
301 if self.ifaces.contains_key(&ifname) { return };
302 let z = self.ifacecache.get(ifname, |i| {
303 i.add_m(super::leaves::new_method("Get".into(), Default::default(),
304 M::make_method(|m| m.path.prop_get(m)))
305 .inarg::<&str,_>("interface_name")
306 .inarg::<&str,_>("property_name")
307 .outarg::<Variant<()>,_>("value"))
308 .add_m(super::leaves::new_method("GetAll".into(), Default::default(),
309 M::make_method(|m| m.path.prop_get_all(m)))
310 .inarg::<&str,_>("interface_name")
311 .outarg::<Dict<&str, Variant<()>, ()>,_>("props"))
312 .add_m(super::leaves::new_method("Set".into(), Default::default(),
313 M::make_method(|m| m.path.prop_set(m)))
314 .inarg::<&str,_>("interface_name")
315 .inarg::<&str,_>("property_name")
316 .inarg::<Variant<bool>,_>("value"))
317 });
318 self.ifaces.insert(z.name.clone(), z);
319 }
320 }
321
new_objectpath<M: MethodType<D>, D: DataType>(n: Path<'static>, d: D::ObjectPath, cache: Arc<IfaceCache<M, D>>) -> ObjectPath<M, D>322 pub fn new_objectpath<M: MethodType<D>, D: DataType>(n: Path<'static>, d: D::ObjectPath, cache: Arc<IfaceCache<M, D>>)
323 -> ObjectPath<M, D> {
324 ObjectPath { name: Arc::new(n), data: d, ifaces: ArcMap::new(), ifacecache: cache, default_iface: None }
325 }
326
327
328 /// A collection of object paths.
329 #[derive(Debug, Default)]
330 pub struct Tree<M: MethodType<D>, D: DataType> {
331 paths: ArcMap<Arc<Path<'static>>, ObjectPath<M, D>>,
332 data: D::Tree,
333 }
334
335 impl<M: MethodType<D>, D: DataType> Tree<M, D> {
336 /// Builder function that adds an object path to this tree.
337 ///
338 /// Note: This does not register a path with the connection, so if the tree is currently registered,
339 /// you might want to call Connection::register_object_path to add the path manually.
add<I: Into<Arc<ObjectPath<M, D>>>>(mut self, s: I) -> Self340 pub fn add<I: Into<Arc<ObjectPath<M, D>>>>(mut self, s: I) -> Self {
341 self.insert(s);
342 self
343 }
344
345 /// Get a reference to an object path from the tree.
get(&self, p: &Path<'static>) -> Option<&Arc<ObjectPath<M, D>>>346 pub fn get(&self, p: &Path<'static>) -> Option<&Arc<ObjectPath<M, D>>> {
347 self.paths.get(p)
348 }
349
350 /// Iterates over object paths in this tree.
iter<'a>(&'a self) -> Iter<'a, ObjectPath<M, D>>351 pub fn iter<'a>(&'a self) -> Iter<'a, ObjectPath<M, D>> { IterE::Path(self.paths.values()).into() }
352
353 /// Non-builder function that adds an object path to this tree.
354 ///
355 /// Note: This does not register a path with the connection, so if the tree is currently registered,
356 /// you might want to call Connection::register_object_path to add the path manually.
insert<I: Into<Arc<ObjectPath<M, D>>>>(&mut self, s: I)357 pub fn insert<I: Into<Arc<ObjectPath<M, D>>>>(&mut self, s: I) {
358 let m = s.into();
359 self.paths.insert(m.name.clone(), m);
360 }
361
362
363 /// Remove a object path from the Tree. Returns the object path removed, or None if not found.
364 ///
365 /// Note: This does not unregister a path with the connection, so if the tree is currently registered,
366 /// you might want to call Connection::unregister_object_path to remove the path manually.
remove(&mut self, p: &Path<'static>) -> Option<Arc<ObjectPath<M, D>>>367 pub fn remove(&mut self, p: &Path<'static>) -> Option<Arc<ObjectPath<M, D>>> {
368 // There is no real reason p needs to have a static lifetime; but
369 // the borrow checker doesn't agree. :-(
370 self.paths.remove(p)
371 }
372
373 /// Registers or unregisters all object paths in the tree.
set_registered(&self, c: &Connection, b: bool) -> Result<(), Error>374 pub fn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> {
375 let mut regd_paths = Vec::new();
376 for p in self.paths.keys() {
377 if b {
378 match c.register_object_path(p) {
379 Ok(()) => regd_paths.push(p.clone()),
380 Err(e) => {
381 while let Some(rp) = regd_paths.pop() {
382 c.unregister_object_path(&rp);
383 }
384 return Err(e)
385 }
386 }
387 } else {
388 c.unregister_object_path(p);
389 }
390 }
391 Ok(())
392 }
393
394 /// This method takes an `ConnectionItem` iterator (you get it from `Connection::iter()`)
395 /// 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, D>396 pub fn run<'a, I: Iterator<Item=ConnectionItem>>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M, D> {
397 TreeServer { iter: i, tree: &self, conn: c }
398 }
399
400 /// Handles a message.
401 ///
402 /// Will return None in case the object path was not
403 /// found in this tree, or otherwise a list of messages to be sent back.
handle(&self, m: &Message) -> Option<Vec<Message>>404 pub fn handle(&self, m: &Message) -> Option<Vec<Message>> {
405 if m.msg_type() != MessageType::MethodCall { None }
406 else { m.path().and_then(|p| self.paths.get(&p).map(|s| s.handle(m, &self)
407 .unwrap_or_else(|e| vec!(e.to_message(m))))) }
408 }
409
410
children(&self, o: &ObjectPath<M, D>, direct_only: bool) -> Vec<&ObjectPath<M, D>>411 fn children(&self, o: &ObjectPath<M, D>, direct_only: bool) -> Vec<&ObjectPath<M, D>> {
412 let parent: &str = &o.name;
413 let plen = parent.len()+1;
414 self.paths.values().filter_map(|v| {
415 let k: &str = &v.name;
416 if !k.starts_with(parent) || k.len() <= plen || &k[plen-1..plen] != "/" {None} else {
417 let child = &k[plen..];
418 if direct_only && child.contains("/") {None} else {Some(&**v)}
419 }
420 }).collect()
421 }
422
423 /// Get associated data
get_data(&self) -> &D::Tree424 pub fn get_data(&self) -> &D::Tree { &self.data }
425
426 }
427
new_tree<M: MethodType<D>, D: DataType>(d: D::Tree) -> Tree<M, D>428 pub fn new_tree<M: MethodType<D>, D: DataType>(d: D::Tree) -> Tree<M, D> {
429 Tree { paths: ArcMap::new(), data: d }
430 }
431
432 impl<M: MethodType<D>, D: DataType> MsgHandler for Tree<M, D> {
handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult>433 fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
434 self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
435 }
handler_type(&self) -> MsgHandlerType436 fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
437 }
438
439 impl<M: MethodType<D>, D: DataType> MsgHandler for Arc<Tree<M, D>> {
handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult>440 fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
441 self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
442 }
handler_type(&self) -> MsgHandlerType443 fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
444 }
445
446 /// An iterator adapter that handles incoming method calls.
447 ///
448 /// Method calls that match an object path in the tree are handled and consumed by this
449 /// iterator. Other messages are passed through.
450 pub struct TreeServer<'a, I, M: MethodType<D> + 'a, D: DataType + 'a> {
451 iter: I,
452 conn: &'a Connection,
453 tree: &'a Tree<M, D>,
454 }
455
456 impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType<D>, D: DataType + 'a> Iterator for TreeServer<'a, I, M, D> {
457 type Item = ConnectionItem;
458
next(&mut self) -> Option<ConnectionItem>459 fn next(&mut self) -> Option<ConnectionItem> {
460 loop {
461 let n = self.iter.next();
462 if let &Some(ConnectionItem::MethodCall(ref msg)) = &n {
463 if let Some(v) = self.tree.handle(&msg) {
464 // Probably the wisest is to ignore any send errors here -
465 // maybe the remote has disconnected during our processing.
466 for m in v { let _ = self.conn.send(m); };
467 continue;
468 }
469 }
470 return n;
471 }
472 }
473 }
474
475
476 #[test]
test_iter()477 fn test_iter() {
478 let f = super::Factory::new_fn::<()>();
479 let t = f.tree(())
480 .add(f.object_path("/echo", ()).introspectable()
481 .add(f.interface("com.example.echo", ())
482 .add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
483 .add_p(f.property::<i32,_>("EchoCount", ()))
484 .add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated()
485 )
486 )).add(f.object_path("/echo/subpath", ()));
487
488 let paths: Vec<_> = t.iter().collect();
489 assert_eq!(paths.len(), 2);
490 }
491
492 #[test]
test_set_default_interface()493 fn test_set_default_interface() {
494 let iface_name: IfaceName<'_> = "com.example.echo".into();
495 let f = super::Factory::new_fn::<()>();
496 let t = f.object_path("/echo", ()).default_interface(iface_name.clone());
497 assert_eq!(t.default_iface, Some(iface_name));
498 }
499
500
501 #[test]
test_introspection()502 fn test_introspection() {
503 let f = super::Factory::new_fn::<()>();
504 let t = f.object_path("/echo", ()).introspectable()
505 .add(f.interface("com.example.echo", ())
506 .add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
507 .add_p(f.property::<i32,_>("EchoCount", ()))
508 .add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated())
509 );
510
511 let actual_result = t.introspect(&f.tree(()).add(f.object_path("/echo/subpath", ())));
512 println!("\n=== Introspection XML start ===\n{}\n=== Introspection XML end ===", actual_result);
513
514 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">
515 <node name="/echo">
516 <interface name="com.example.echo">
517 <method name="Echo">
518 <arg name="request" type="s" direction="in"/>
519 <arg name="reply" type="s" direction="out"/>
520 </method>
521 <property name="EchoCount" type="i" access="read"/>
522 <signal name="Echoed">
523 <arg name="data" type="s"/>
524 <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
525 </signal>
526 </interface>
527 <interface name="org.freedesktop.DBus.Introspectable">
528 <method name="Introspect">
529 <arg name="xml_data" type="s" direction="out"/>
530 </method>
531 </interface>
532 <interface name="org.freedesktop.DBus.Properties">
533 <method name="Get">
534 <arg name="interface_name" type="s" direction="in"/>
535 <arg name="property_name" type="s" direction="in"/>
536 <arg name="value" type="v" direction="out"/>
537 </method>
538 <method name="GetAll">
539 <arg name="interface_name" type="s" direction="in"/>
540 <arg name="props" type="a{sv}" direction="out"/>
541 </method>
542 <method name="Set">
543 <arg name="interface_name" type="s" direction="in"/>
544 <arg name="property_name" type="s" direction="in"/>
545 <arg name="value" type="v" direction="in"/>
546 </method>
547 </interface>
548 <node name="subpath"/>
549 </node>"##;
550
551 assert_eq!(expected_result, actual_result);
552 }
553
554