/// NOTE: No longer used - replaced with files in the "tree" directory.
#![allow(dead_code)]
use {MessageItem, Message, MessageType, Connection, ConnectionItem, Error, ErrorName}; use {Signature, Member, Path}; use Interface as IfaceName; use std::cell::RefCell; use std::sync::{Arc, Mutex}; use std::collections::BTreeMap; use std::marker::PhantomData; use std::ffi::{CStr, CString}; use std::fmt; usesuper::arg;
// Small helper struct to reduce memory somewhat for objects without annotations #[derive(Clone, Debug, Default)] struct Annotations(Option<BTreeMap<String, String>>);
/// Result containing the Messages returned from the Method, or a MethodErr. pubtype MethodResult = Result<Vec<Message>, MethodErr>;
/// A MethodType that wraps an Fn function pubstruct MethodFn<'a>(Box<Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult + 'a>); /// A MethodType that wraps an FnMut function. Calling this recursively will cause a refcell panic. pubstruct MethodFnMut<'a>(Box<RefCell<FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult + 'a>>); /// A MethodType that wraps an Fn+Send+Sync function, so it can be called from several threads in parallel. pubstruct MethodSync(Box<Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static>);
impl<M> Interface<M> { /// Adds a method to the interface. pubfn add_m(mutself, m: Method<M>) -> Self { self.methods.insert(m.name.clone(), Arc::new(m)); self } /// Adds a signal to the interface. pubfn add_s(mutself, s: Signal) -> Self { self.signals.insert(s.name.clone(), Arc::new(s)); self } /// Adds a signal to the interface. Lets you keep another clone of the signal /// (which you can use to emit the signal, once it belongs to an object path). /// /// Note: You are not allowed to add a signal to more than one interface. pubfn add_s_arc(mutself, s: Arc<Signal>) -> Self { self.signals.insert(s.name.clone(), s); self } /// Adds a signal to the interface. Returns a reference to the signal /// (which you can use to emit the signal, once it belongs to an object path). pubfn add_s_ref(&mutself, s: Signal) -> Arc<Signal> { let s = Arc::new(s); self.signals.insert(s.name.clone(), s.clone());
s
}
/// Adds a property to the interface. pubfn add_p(mutself, p: Property<M>) -> Self { self.properties.insert(p.name.clone(), Arc::new(p)); self } /// Adds a property to the interface. Lets you keep another clone of the property /// (which you can use to get and set the current value of the property). /// /// Note: You are not allowed to add a property to more than one interface. Later function calls might panic if you do so. pubfn add_p_arc(mutself, p: Arc<Property<M>>) -> Self { self.properties.insert(p.name.clone(), p); self } /// Adds a property to the interface. Returns a reference to the property /// (which you can use to get and set the current value of the property). pubfn add_p_ref(&mutself, p: Property<M>) -> Arc<Property<M>> { let p = Arc::new(p); self.properties.insert(p.name.clone(), p.clone());
p
}
/// Add an annotation to this Inteface. pubfn annotate<N: Into<String>, V: Into<String>>(mutself, name: N, value: V) -> Self { self.anns.insert(name, value); self
} /// Add an annotation that this entity is deprecated. pubfn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)] /// Enumerates the different signaling behaviors a Property can have /// to being changed. pubenum EmitsChangedSignal { /// The Property emits a signal that includes the new value. True, /// The Property emits a signal that does not include the new value.
Invalidates, /// The Property cannot be changed. Const, /// The Property does not emit a signal when changed. False,
}
#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)] /// The possible access characteristics a Property can have. pubenum Access { /// The Property can only be read (Get).
Read, /// The Property can be read or written.
ReadWrite, /// The Property can only be written (Set).
Write,
}
impl<M: MethodType> Property<M> { /// Gets the value of the Property. pubfn get_value(&self) -> MessageItem { self.value.lock().unwrap().clone()
}
/// Gets the signal (if any) associated with the Property. pubfn get_signal(&self) -> Option<Message> { self.owner.lock().unwrap().as_ref().map(|&(ref p, ref i)| {
Message::signal(&p, &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
.append(String::from(&***i))
})
}
/// Returns error if "emits" is "Const", and the property is in a /// tree. Returns messages to be sent over a connection, this /// could be the PropertiesChanged signal. pubfn set_value(&self, m: MessageItem) -> Result<Vec<Message>,()> { let ss = matchself.emits {
EmitsChangedSignal::False => None,
EmitsChangedSignal::Const => ifself.get_signal().is_some() { return Err(()) } else { None },
EmitsChangedSignal::True => self.get_signal().map(|s|
s.append2(arg::Dict::new(vec!((&**self.name, arg::Variant(m.clone())))), arg::Array::<&str, _>::new(vec!()))
),
EmitsChangedSignal::Invalidates => self.get_signal().map(|s| {
s.append2(arg::Dict::<&str, arg::Variant<MessageItem>, _>::new(vec!()), arg::Array::new(vec!(&**self.name)))
}),
};
*self.value.lock().unwrap() = m;
Ok(ss.map(|s| vec!(s)).unwrap_or(vec!()))
}
/// Builder method that allows setting the Property's signal /// behavior when changed. pubfn emits_changed(mutself, e: EmitsChangedSignal) -> Self { self.emits = e;
assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const); self
}
/// Builder method that allows setting the Property as readable, /// writable, or both. pubfn access(mutself, e: Access) -> Self { self.rw = e;
assert!(self.rw == Access::Read || self.emits != EmitsChangedSignal::Const); self
}
/// Helper method to check accessibility before getting a value. pubfn remote_get(&self, _: &Message) -> Result<MessageItem, MethodErr> { // TODO: We should be able to call a user-defined callback here instead... ifself.rw == Access::Write { return Err(MethodErr::failed(&format!("Property {} is write only", &self.name))) }
Ok(self.get_value())
}
/// Helper method to verify and extract a MessageItem from a Set message pubfn verify_remote_set(&self, m: &Message) -> Result<MessageItem, MethodErr> { let items = m.get_items(); let s: &MessageItem = try!(items.get(2).ok_or_else(|| MethodErr::no_arg())
.and_then(|i| i.inner().map_err(|_| MethodErr::invalid_arg(&i))));
impl Property<MethodSync> { /// Sets a callback to be called when a "Set" call is coming in from the remote side. /// Might change to something more ergonomic. /// For multi-thread use. pubfn on_set<H>(mutself, m: H) -> Self where H: Fn(&Message, &ObjectPath<MethodSync>, &Tree<MethodSync>) -> MethodResult + Send + Sync + 'static { self.set_cb = Some(MethodSync::box_method(m)); self
}
}
impl<'a> Property<MethodFn<'a>> { /// Sets a callback to be called when a "Set" call is coming in from the remote side. /// Might change to something more ergonomic. /// For single-thread use. pubfn on_set<H: 'a>(mut self, m: H) -> Self where H: Fn(&Message, &ObjectPath<MethodFn<'a>>, &Tree<MethodFn<'a>>) -> MethodResult { self.set_cb = Some(MethodFn(Box::new(m))); self
}
}
impl<'a> Property<MethodFnMut<'a>> { /// Sets a callback to be called when a "Set" call is coming in from the remote side. /// Might change to something more ergonomic. /// For single-thread use. pubfn on_set<H: 'a>(mut self, m: H) -> Self where H: FnMut(&Message, &ObjectPath<MethodFnMut<'a>>, &Tree<MethodFnMut<'a>>) -> MethodResult { self.set_cb = Some(MethodFnMut(Box::new(RefCell::new(m)))); self
}
}
#[derive(Debug)] /// A D-Bus Signal. pubstruct Signal {
name: Arc<Member<'static>>,
arguments: Vec<Argument>,
owner: Mutex<Option<(Arc<Path<'static>>, Arc<IfaceName<'static>>)>>,
anns: Annotations,
}
impl Signal { /// Returns a message which emits the signal when sent. /// Panics if the signal is not inserted in an object path. pubfn emit(&self, items: &[MessageItem]) -> Message { letmut m = { let lock = self.owner.lock().unwrap(); let &(ref p, ref i) = lock.as_ref().unwrap();
Message::signal(p, i, &self.name)
};
m.append_items(items);
m
}
/// Returns a message which emits the signal when sent. /// Panics if the signal is not inserted in an object path. /// /// Same as "emit" but does not take a "MessageItem" argument. pubfn msg(&self) -> Message { self.emit(&[]) }
/// Builder method that adds an Argument to the Signal. pubfn arg<A: Into<Argument>>(mutself, a: A) -> Self { self.arguments.push(a.into()); self } /// Builder method that adds an Argument to the Signal. pubfn sarg<A: arg::Arg, S: Into<String>>(mutself, s: S) -> Self { self.arguments.push((s.into(), A::signature()).into()); self } /// Builder method that adds multiple "rguments to the Signel. pubfn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mutself, a: A) -> Self { self.arguments.extend(a.into_iter().map(|b| b.into())); self
}
/// Add an annotation to this Signal. pubfn annotate<N: Into<String>, V: Into<String>>(mutself, name: N, value: V) -> Self { self.anns.insert(name, value); self
} /// Add an annotation that this entity is deprecated. pubfn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
}
fn prop_set(&self, m: &Message, o: &ObjectPath<M>, t: &Tree<M>) -> MethodResult { let (iname, p) = m.get2(); let iface = try!(self.get_iface(iname)); let prop_name: &str = try!(p.ok_or_else(|| MethodErr::invalid_arg(&1))); let prop: &Property<M> = try!(iface.properties.get(&String::from(prop_name))
.ok_or_else(|| MethodErr::no_property(&prop_name))); letmut r = try!(prop.remote_set(m, o, t));
r.push(m.method_return());
Ok(r)
}
fn prop_get(&self, m: &Message) -> MethodResult { let (iname, p) = m.get2(); let iface = try!(self.get_iface(iname)); let prop_name: &str = try!(p.ok_or_else(|| MethodErr::invalid_arg(&1))); let prop: &Property<M> = try!(iface.properties.get(&String::from(prop_name))
.ok_or_else(|| MethodErr::no_property(&prop_name))); let r = try!(prop.remote_get(m));
Ok(vec!(m.method_return().append1(arg::Variant(r))))
}
fn prop_get_all(&self, m: &Message) -> MethodResult { let iface = try!(self.get_iface(m.get1())); letmut q = vec!(); for v in iface.properties.values() {
q.push((&**v.name, arg::Variant(try!(v.remote_get(m)))));
}
Ok(vec!(m.method_return().append1(arg::Dict::new(q))))
}
fn add_property_handler(&mutself) { let ifname = IfaceName::from("org.freedesktop.DBus.Properties"); ifself.ifaces.contains_key(&ifname) { return }; let f: Factory<M> = Factory(PhantomData);
let i = Interface::<M>::new(ifname)
.add_m(f.method_sync("Get", |m,o,_| o.prop_get(m) )
.inarg::<&str,_>("interface_name")
.inarg::<&str,_>("property_name")
.outarg::<arg::Variant<()>,_>("value"))
.add_m(f.method_sync("GetAll", |m,o,_| o.prop_get_all(m))
.inarg::<&str,_>("interface_name")
.outarg::<arg::Dict<&str, arg::Variant<()>, ()>,_>("props"))
.add_m(f.method_sync("Set", |m,o,t| o.prop_set(m, o, t))
.inarg::<&str,_>("interface_name")
.inarg::<&str,_>("property_name")
.inarg::<arg::Variant<()>,_>("value")); self.ifaces.insert(i.name.clone(), Arc::new(i));
}
/// Add an Interface to this Object Path. pubfn add(mutself, p: Interface<M>) -> Self { use std::mem; for s in p.signals.values() { let n = Some((self.name.clone(), p.name.clone())); let o = mem::replace(&mut *s.owner.lock().unwrap(), n);
assert!(o.is_none(), "Signal {} already added to object path", s.name);
}; for s in p.properties.values() { let n = Some((self.name.clone(), p.name.clone())); let o = mem::replace(&mut *s.owner.lock().unwrap(), n);
assert!(o.is_none(), "Property {} already added to object path", s.name);
}; if !p.properties.is_empty() { self.add_property_handler(); } self.ifaces.insert(p.name.clone(), Arc::new(p)); self
}
/// Adds introspection support for this object path. pubfn introspectable(self) -> Self { let ifname: IfaceName = "org.freedesktop.DBus.Introspectable".into(); ifself.ifaces.contains_key(&ifname) { returnself }; let f: Factory<M> = Factory(PhantomData); self.add(Interface::<M>::new(ifname)
.add_m(f.method_sync("Introspect",
|m,o,t| Ok(vec!(m.method_return().append(o.introspect(t)))))
.out_arg(("xml_data", "s"))))
}
fn handle(&self, m: &Message, t: &Tree<M>) -> MethodResult { let i = try!(m.interface().and_then(|i| self.ifaces.get(&i)).ok_or(
("org.freedesktop.DBus.Error.UnknownInterface", "Unknown interface"))); let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or(
("org.freedesktop.DBus.Error.UnknownMethod", "Unknown method")));
me.call(m, &self, t)
}
/// 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(self) -> Self { let ifname: IfaceName = "org.freedesktop.DBus.ObjectManager".into(); ifself.ifaces.contains_key(&ifname) { returnself }; let f: Factory<M> = Factory(PhantomData); self.add(Interface::<M>::new(ifname)
.add_m(f.method_sync("GetManagedObjects",
|m,o,t| Ok(vec!(m.method_return().append(o.get_managed_objects(t)))))
.out_arg("a{oa{sa{sv}}}")))
}
}
/// 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: 'a> {
iter: I,
conn: &'a Connection,
tree: &'a Tree<M>,
}
impl<'a, I: Iterator<Item=ConnectionItem>, M: 'a + MethodType> Iterator for TreeServer<'a, I, M> { 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;
}
}
}
/// A collection of object paths. #[derive(Debug)] pubstruct Tree<M> {
paths: ArcMap<Path<'static>, ObjectPath<M>>
}
impl<M: MethodType> Tree<M> {
fn children(&self, o: &ObjectPath<M>, direct_only: bool) -> Vec<&ObjectPath<M>> { 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()
}
/// Add an Object Path to this Tree. /// /// Note: This does not unregister 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(mutself, p: ObjectPath<M>) -> Self { self.paths.insert(p.name.clone(), Arc::new(p)); self
}
/// Adds an ObjectPath to this Tree. Returns a reference to the ObjectPath. /// The note for add() also applies here. pubfn add_o_ref(&mutself, p: ObjectPath<M>) -> Arc<ObjectPath<M>> { let name = p.name.clone(); let o = Arc::new(p); self.paths.insert(name, o.clone());
o
}
/// 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>>> { // 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(())
}
/// Handles a message. Will return None in case the object path was not /// found, 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!(m.error(&e.0, &CString::new(e.1).unwrap()))))) }
}
/// 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> {
TreeServer { iter: i, tree: &self, conn: c }
}
}
/// The factory is used to create object paths, interfaces, methods etc. /// /// There are three factories: /// /// **Fn** - all methods are `Fn()`. /// /// **FnMut** - all methods are `FnMut()`. This means they can mutate their environment, /// which has the side effect that if you call it recursively, it will RefCell panic. /// /// **Sync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods /// can be called from different threads in parallel. #[derive(Debug, Copy, Clone)] pubstruct Factory<M>(PhantomData<M>);
impl<'a> Factory<MethodFn<'a>> {
/// Creates a new factory for single-thread use. pubfn new_fn() -> Self { Factory(PhantomData) }
/// Creates a new method for single-thread use. pubfn 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<'static>> {
Method::new(t.into(), MethodFn(Box::new(handler)))
}
/// Creates a new property for single-thread use. pubfn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFn<'b>> {
Property::new(t.into(), i.into())
}
/// Creates a new interface for single-thread use. pubfn interface<'b, T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodFn<'b>> { Interface::new(t.into()) }
/// Creates a new tree for single-thread use. pubfn tree<'b>(&self) -> Tree<MethodFn<'b>> { Tree { paths: BTreeMap::new() }}
/// Creates a new object path for single-thread use. pubfn object_path<'b, T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodFn<'b>> { ObjectPath::new(t.into()) }
}
impl<'a> Factory<MethodFnMut<'a>> {
/// Creates a new factory for single-thread + mutable fns use. pubfn new_fnmut() -> Self { Factory(PhantomData) }
/// Creates a new method for single-thread use. /// This method can mutate its environment, so it will panic in case /// it is called recursively. pubfn 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<'static>> {
Method::new(t.into(), MethodFnMut(Box::new(RefCell::new(handler))))
}
/// Creates a new mutable property for single-thread use. pubfn property<'b, T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodFnMut<'b>> {
Property::new(t.into(), i.into())
}
/// Creates a new mutable interface for single-thread use. pubfn interface<'b, T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodFnMut<'b>> { Interface::new(t.into()) }
/// Creates a new mutable tree for single-thread use. pubfn tree<'b>(&self) -> Tree<MethodFnMut<'b>> { Tree { paths: BTreeMap::new() }}
/// Creates a new mutable object path for single-thread use. pubfn object_path<'b, T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodFnMut<'b>> { ObjectPath::new(t.into()) }
}
impl Factory<MethodSync> {
/// Creates a new factory for multi-thread use. /// Trees created will be able to Send and Sync, i e, /// it can handle several messages in parallel. pubfn new_sync() -> Self { Factory(PhantomData) }
/// Creates a new method for multi-thread use. /// This puts bounds on the callback to enable it to be called from several threads /// in parallel. pubfn 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<'static>> {
Method::new(t.into(), MethodSync(Box::new(handler)))
}
/// Creates a new property for multi-threaded use. pubfn property<T: Into<String>, I: Into<MessageItem>>(&self, t: T, i: I) -> Property<MethodSync> {
Property::new(t.into(), i.into())
}
/// Creates a new interface for multi-threaded use. pubfn interface<T: Into<IfaceName<'static>>>(&self, t: T) -> Interface<MethodSync> { Interface::new(t.into()) }
/// Creates a new tree for multi-threaded use. pubfn tree(&self) -> Tree<MethodSync> { Tree { paths: BTreeMap::new() }}
/// Creates a new object path for multi-threaded use. pubfn object_path<T: Into<Path<'static>>>(&self, t: T) -> ObjectPath<MethodSync> { ObjectPath::new(t.into()) }
}
impl<M> Factory<M> { /// Create a Signal. pubfn signal<T: Into<Member<'static>>>(&self, t: T) -> Signal {
Signal { name: Arc::new(t.into()), arguments: vec!(), owner: Mutex::new(None), anns: Annotations::new() }
}
}
impl<M: MethodType> Factory<M> { /// Creates a new method with bounds enough to be used in all trees. pubfn 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<'static>> {
Method::new(t.into(), M::box_method(handler))
}
}
#[test] fn factory_test() { let f = Factory::new_fn();
f.interface("com.example.hello").deprecated(); let b = 5i32;
f.method("GetSomething", |m,_,_| Ok(vec!({ letmut z = m.method_return(); z.append_items(&[b.into()]); z}))); let t = f.tree().add(f.object_path("/funghi").add(f.interface("a.b.c").deprecated())); 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"));
assert_eq!(t.children(t.paths.get(&Path::from("/a")).unwrap(), true).len(), 1);
}
#[test] fn test_sync_prop() { let f = Factory::new_sync(); letmut i = f.interface("com.example.echo"); let p = i.add_p_ref(f.property("EchoCount", 7i32)); let tree1 = Arc::new(f.tree().add(f.object_path("/echo").introspectable().add(i))); let tree2 = tree1.clone();
println!("{:#?}", tree2);
::std::thread::spawn(move || { let r = p.set_value(9i32.into()).unwrap(); let signal = r.get(0).unwrap();
assert_eq!(signal.msg_type(), MessageType::Signal); letmut msg = Message::new_method_call("com.example.echoserver", "/echo", "com.example", "dummy").unwrap(); super::message::message_set_serial(&mut msg, 3);
tree2.handle(&msg);
});
letmut msg = Message::new_method_call("com.example.echoserver", "/echo", "org.freedesktop.DBus.Properties", "Get").unwrap()
.append("com.example.echo").append("EchoCount"); super::message::message_set_serial(&mut msg, 4); let r = tree1.handle(&msg).unwrap(); let r1 = r.get(0).unwrap();
println!("{:?}", r1.get_items()); let vv: super::arg::Variant<i32> = r1.get1().unwrap();
assert!(vv.0 == 7 || vv.0 == 9);
}
/* This test case no longer works, for unknown reason, see https://github.com/diwic/dbus-rs/issues/27
#[test] fn prop_server() { let setme: Arc<RefCell<Option<Arc<Property<_>>>>>; // Yikes!
setme = Arc::new(RefCell::new(None)); let f = Factory::new_fnmut(); letmut i = f.interface("com.example.dbus.rs"); let count = i.add_p_ref(f.property("changes", 0i32)); let count2 = count.clone(); let setme2 = setme.clone(); let setme3 = Arc::new(f.property("setme", 0u8).access(Access::ReadWrite).on_set(move|m,_,_| { let ss2 = setme2.borrow(); let ss = ss2.as_ref().unwrap(); let s = try!(ss.verify_remote_set(m)); let r = try!(ss.set_value(s).map_err(|_| MethodErr::ro_property(&ss.name))); let v: i32 = count2.get_value().inner().unwrap();
count2.set_value((v + 1).into()).unwrap();
Ok(r)
}));
*setme.borrow_mut() = Some(setme3.clone()); let i = i.add_p_arc(setme3);
let tree = f.tree().add(f.object_path("/example").add(i));
letmut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Get").unwrap()
.append("com.example.dbus.rs").append("changes"); super::message::message_set_serial(&mut msg, 10); let r = tree.handle(&msg).unwrap(); let r1 = r.get(0).unwrap(); let ii = r1.get_items(); let vv: &MessageItem = ii.get(0).unwrap().inner().unwrap(); let v: i32 = vv.inner().unwrap();
assert_eq!(v, 0);
let c: i32 = count.get_value().inner().unwrap();
assert_eq!(c, 1);
}
#[test] fn test_introspection() { let f = Factory::new_sync(); 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("EchoCount", 7i32))
.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.