impl<M: MethodType<D>, D: DataType> Interface<M, D> { /// Builder function that adds a method to the interface. pubfn add_m<I: Into<Arc<Method<M, D>>>>(mutself, m: I) -> Self { let m = m.into(); self.methods.insert(m.get_name().clone(), m); self
}
/// Builder function that adds a signal to the interface. pubfn add_s<I: Into<Arc<Signal<D>>>>(mutself, s: I) -> Self { let m = s.into(); self.signals.insert(m.get_name().clone(), m); self
}
/// Builder function that adds a property to the interface. pubfn add_p<I: Into<Arc<Property<M, D>>>>(mutself, p: I) -> Self { let m = p.into(); self.properties.insert(m.get_name().to_owned(), m); self
}
/// Builder function that adds an annotation to this interface. pubfn annotate<N: Into<String>, V: Into<String>>(mutself, name: N, value: V) -> Self { self.anns.insert(name, value); self
}
/// Builder function that adds an annotation that this entity is deprecated. pubfn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Get interface name pubfn get_name(&self) -> &IfaceName<'static> { &self.name }
/// Get associated data pubfn get_data(&self) -> &D::Interface { &self.data }
/// Iterates over methods implemented by this interface. pubfn iter_m<'a>(&'a self) -> Iter<'a, Method<M, D>> { IterE::Member(self.methods.values()).into() }
/// Iterates over signals implemented by this interface. pubfn iter_s<'a>(&'a self) -> Iter<'a, Signal<D>> { IterE::Member(self.signals.values()).into() }
/// Iterates over properties implemented by this interface. pubfn iter_p<'a>(&'a self) -> Iter<'a, Property<M, D>> { IterE::String(self.properties.values()).into() }
}
#[derive(Debug)] /// Cache of built-in interfaces, in order to save memory when many object paths implement the same interface(s). pubstruct IfaceCache<M: MethodType<D>, D: DataType>(Mutex<ArcMap<IfaceName<'static>, Interface<M, D>>>);
impl<M: MethodType<D>, D: DataType> IfaceCache<M, D> where D::Interface: Default { pubfn 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> { let s2 = s.clone().into(); letmut m = self.0.lock().unwrap();
m.entry(s2).or_insert_with(|| { let i = new_interface(s.into(), Default::default());
Arc::new(f(i))
}).clone()
}
}
fn get_managed_objects(&self, m: &MethodInfo<M, D>) -> MethodResult { use arg::{Dict, Variant}; letmut paths = m.tree.children(&self, false);
paths.push(&self); letmut result = Ok(()); letmut r = m.msg.method_return();
{ letmut i = arg::IterAppend::new(&mut r);
i.append_dict(&Signature::make::<Path>(), &Signature::make::<Dict<&str,Dict<&str,Variant<()>,()>,()>>(), |ii| { for p in paths {
ii.append_dict_entry(|pi| {
pi.append(&*p.name);
pi.append_dict(&Signature::make::<&str>(), &Signature::make::<Dict<&str,Variant<()>,()>>(), |pii| { for ifaces in p.ifaces.values() { let m2 = MethodInfo { msg: m.msg, path: p, iface: ifaces, tree: m.tree, method: m.method };
pii.append_dict_entry(|ppii| {
ppii.append(&**ifaces.name);
result = prop_append_dict(ppii, ifaces.properties.values().map(|v| &**v), &m2);
}); if result.is_err() { break; }
}
});
}); if result.is_err() { break; }
}
});
} try!(result);
Ok(vec!(r))
}
fn handle(&self, m: &Message, t: &Tree<M, D>) -> MethodResult { let iname = m.interface().or_else(|| { self.default_iface.clone() }); let i = try!(iname.and_then(|i| self.ifaces.get(&i)).ok_or_else(|| MethodErr::no_interface(&yle='color:blue'>""))); let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or_else(|| MethodErr::no_method(&style='color:blue'>""))); let minfo = MethodInfo { msg: m, tree: t, path: self, iface: i, method: me };
me.call(&minfo)
}
}
impl<M: MethodType<D>, D: DataType> ObjectPath<M, D> where <D as DataType>::Interface: Default, <D as DataType>::Method: Default
{ /// Adds introspection support for this object path. pubfn introspectable(self) -> Self { let z = self.ifacecache.get_factory("org.freedesktop.DBus.Introspectable", || { let f = Factory::from(self.ifacecache.clone());
methodtype::org_freedesktop_dbus_introspectable_server(&f, Default::default())
}); self.add(z)
}
/// Builder function that adds a interface to the object path. pubfn add<I: Into<Arc<Interface<M, D>>>>(mutself, s: I) -> Self { let m = s.into(); if !m.properties.is_empty() { self.add_property_handler(); } self.ifaces.insert(m.name.clone(), m); self
}
/// Builder function that sets what interface should be dispatched on an incoming /// method call without interface. pubfn default_interface(mutself, i: IfaceName<'static>) -> Self { self.default_iface = Some(i); self
}
/// Adds ObjectManager support for this object path. /// /// It is not possible to add/remove interfaces while the object path belongs to a tree, /// hence no InterfacesAdded / InterfacesRemoved signals are sent. pubfn object_manager(mutself) -> Self { use arg::{Variant, Dict}; let ifname = IfaceName::from("org.freedesktop.DBus.ObjectManager"); ifself.ifaces.contains_key(&ifname) { returnself }; let z = self.ifacecache.get(ifname, |i| {
i.add_m(super::leaves::new_method("GetManagedObjects".into(), Default::default(),
M::make_method(|m| m.path.get_managed_objects(m)))
.outarg::<Dict<Path,Dict<&str,Dict<&str,Variant<()>,()>,()>,()>,_>("objpath_interfaces_and_properties"))
}); self.ifaces.insert(z.name.clone(), z); self
}
impl<M: MethodType<D>, D: DataType> Tree<M, D> { /// Builder function that adds an object path to this tree. /// /// Note: This does not register a path with the connection, so if the tree is currently registered, /// you might want to call Connection::register_object_path to add the path manually. pubfn add<I: Into<Arc<ObjectPath<M, D>>>>(mutself, s: I) -> Self { self.insert(s); self
}
/// Get a reference to an object path from the tree. pubfn get(&self, p: &Path<'static>) -> Option<&Arc<ObjectPath<M, D>>> { self.paths.get(p)
}
/// Iterates over object paths in this tree. pubfn iter<'a>(&'a self) -> Iter<'a, ObjectPath<M, D>> { IterE::Path(self.paths.values()).into() }
/// Non-builder function that adds an object path to this tree. /// /// Note: This does not register a path with the connection, so if the tree is currently registered, /// you might want to call Connection::register_object_path to add the path manually. pubfn insert<I: Into<Arc<ObjectPath<M, D>>>>(&mutself, s: I) { let m = s.into(); self.paths.insert(m.name.clone(), m);
}
/// Remove a object path from the Tree. Returns the object path removed, or None if not found. /// /// Note: This does not unregister a path with the connection, so if the tree is currently registered, /// you might want to call Connection::unregister_object_path to remove the path manually. pubfn remove(&mutself, p: &Path<'static>) -> Option<Arc<ObjectPath<M, D>>> { // There is no real reason p needs to have a static lifetime; but // the borrow checker doesn't agree. :-( self.paths.remove(p)
}
/// Registers or unregisters all object paths in the tree. pubfn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> { letmut regd_paths = Vec::new(); for p inself.paths.keys() { if b { match c.register_object_path(p) {
Ok(()) => regd_paths.push(p.clone()),
Err(e) => { whilelet Some(rp) = regd_paths.pop() {
c.unregister_object_path(&rp);
} return Err(e)
}
}
} else {
c.unregister_object_path(p);
}
}
Ok(())
}
/// This method takes an `ConnectionItem` iterator (you get it from `Connection::iter()`) /// and handles all matching items. Non-matching items (e g signals) are passed through. pubfn run<'a, I: Iterator<Item=ConnectionItem>>(&'a self, c: &'a Connection, i: I) -> TreeServer<'a, I, M, D> {
TreeServer { iter: i, tree: &self, conn: c }
}
/// Handles a message. /// /// Will return None in case the object path was not /// found in this tree, or otherwise a list of messages to be sent back. pubfn handle(&self, m: &Message) -> Option<Vec<Message>> { if m.msg_type() != MessageType::MethodCall { None } else { m.path().and_then(|p| self.paths.get(&p).map(|s| s.handle(m, &self)
.unwrap_or_else(|e| vec!(e.to_message(m))))) }
}
fn children(&self, o: &ObjectPath<M, D>, direct_only: bool) -> Vec<&ObjectPath<M, D>> { let parent: &str = &o.name; let plen = parent.len()+1; self.paths.values().filter_map(|v| { let k: &str = &v.name; if !k.starts_with(parent) || k.len() <= plen || &k[plen-1..plen] != "/" {None} else { let child = &k[plen..]; if direct_only && child.contains("/") {None} else {Some(&**v)}
}
}).collect()
}
/// Get associated data pubfn get_data(&self) -> &D::Tree { &self.data }
}
pubfn new_tree<M: MethodType<D>, D: DataType>(d: D::Tree) -> Tree<M, D> {
Tree { paths: ArcMap::new(), data: d }
}
/// An iterator adapter that handles incoming method calls. /// /// Method calls that match an object path in the tree are handled and consumed by this /// iterator. Other messages are passed through. pubstruct TreeServer<'a, I, M: MethodType<D> + 'a, D: DataType + 'a> {
iter: I,
conn: &'a Connection,
tree: &'a Tree<M, D>,
}
impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType<D>, D: DataType + 'a> Iterator for TreeServer<'a, I, M, D> { type Item = ConnectionItem;
fn next(&mutself) -> Option<ConnectionItem> { loop { let n = self.iter.next(); iflet &Some(ConnectionItem::MethodCall(ref msg)) = &n { iflet Some(v) = self.tree.handle(&msg) { // Probably the wisest is to ignore any send errors here - // maybe the remote has disconnected during our processing. for m in v { let _ = self.conn.send(m); }; continue;
}
} return n;
}
}
}
#[test] fn test_iter() { let f = super::Factory::new_fn::<()>(); let t = f.tree(())
.add(f.object_path("/echo", ()).introspectable()
.add(f.interface("com.example.echo", ())
.add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
.add_p(f.property::<i32,_>("EchoCount", ()))
.add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated()
)
)).add(f.object_path("/echo/subpath", ()));
let paths: Vec<_> = t.iter().collect();
assert_eq!(paths.len(), 2);
}
#[test] fn test_set_default_interface() { let iface_name: IfaceName<'_> = "com.example.echo".into(); let f = super::Factory::new_fn::<()>(); let t = f.object_path("/echo", ()).default_interface(iface_name.clone());
assert_eq!(t.default_iface, Some(iface_name));
}
#[test] fn test_introspection() { let f = super::Factory::new_fn::<()>(); let t = f.object_path("/echo", ()).introspectable()
.add(f.interface("com.example.echo", ())
.add_m(f.method("Echo", (), |_| unimplemented!()).in_arg(("request", "s")).out_arg(("reply", "s")))
.add_p(f.property::<i32,_>("EchoCount", ()))
.add_s(f.signal("Echoed", ()).arg(("data", "s")).deprecated())
);
let actual_result = t.introspect(&f.tree(()).add(f.object_path("/echo/subpath", ())));
println!("\n=== Introspection XML start ===\n{}\n=== Introspection XML end ===", actual_result);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.