// Methods, signals, properties, and interfaces. usesuper::utils::{Argument, Annotations, Introspect, introspect_args}; usesuper::{MethodType, MethodInfo, MethodResult, MethodErr, DataType, PropInfo, MTFn, MTFnMut, MTSync}; use {Member, Signature, Message, Path, MessageItem}; use Interface as IfaceName; use arg; use std::fmt; use std::cell::RefCell; use stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
/// Builder method that adds an "in" Argument to this Method. pubfn in_arg<A: Into<Argument>>(mutself, a: A) -> Self { self.i_args.push(a.into()); self } /// Builder method that adds an "in" Argument to this Method. pubfn inarg<A: arg::Arg, S: Into<String>>(mutself, s: S) -> Self { self.i_args.push((s.into(), A::signature()).into()); self } /// Builder method that adds multiple "in" Arguments to this Method. pubfn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mutself, a: A) -> Self { self.i_args.extend(a.into_iter().map(|b| b.into())); self
}
/// Builder method that adds an "out" Argument to this Method. pubfn out_arg<A: Into<Argument>>(mutself, a: A) -> Self { self.o_args.push(a.into()); self } /// Builder method that adds an "out" Argument to this Method. pubfn outarg<A: arg::Arg, S: Into<String>>(mutself, s: S) -> Self { self.o_args.push((s.into(), A::signature()).into()); self } /// Builder method that adds multiple "out" Arguments to this Method. pubfn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mutself, a: A) -> Self { self.o_args.extend(a.into_iter().map(|b| b.into())); self
}
/// Builder method that adds an annotation to the method. pubfn annotate<N: Into<String>, V: Into<String>>(mutself, name: N, value: V) -> Self { self.anns.insert(name, value); self
} /// Builder method that adds an annotation that this entity is deprecated. pubfn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// 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 Arguments to the Signal. 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") }
/// Get signal name pubfn get_name(&self) -> &Member<'static> { &self.name }
/// Get associated data pubfn get_data(&self) -> &D::Signal { &self.data }
/// Returns a message which emits the signal when sent. /// /// Same as "msg" but also takes a "MessageItem" argument. pubfn emit(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[MessageItem]) -> Message { letmut m = self.msg(p, i);
m.append_items(items);
m
}
/// Returns a message which emits the signal when sent. /// /// Same as "emit" but does not take a "MessageItem" argument. pubfn msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message {
Message::signal(p, i, &self.name)
}
pubfn new_signal<D: DataType>(n: Member<'static>, data: D::Signal) -> Signal<D> {
Signal { name: n, arguments: vec!(), anns: Annotations::new(), data: data }
}
#[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,
}
/// Builder method that allows setting the Property's signal /// behavior when changed. /// /// Note: if e is set to const, the property will be read only. pubfn emits_changed(mutself, e: EmitsChangedSignal) -> Self { self.emits = e; ifself.emits == EmitsChangedSignal::Const { self.rw = Access::Read }; self
}
/// Builder method that determines whether or not setting this property /// will result in an PropertiesChanged signal. Defaults to true. /// /// When set to true (the default), the behaviour is determined by "emits_changed". /// When set to false, no PropertiesChanged signal will be emitted (but the signal /// still shows up in introspection data). /// You can still emit the signal manually by, e g, calling `add_propertieschanged` /// and send the resulting message(s). pubfn auto_emit_on_set(mutself, b: bool) -> Self { self.auto_emit = b; self
}
/// Builder method that allows setting the Property as readable, /// writable, or both. /// /// Note: might modify emits_changed as well, if property is changed to non-readonly and emit is set to "Const". pubfn access(mutself, e: Access) -> Self { self.rw = e; ifself.rw != Access::Read && self.emits == EmitsChangedSignal::Const { self.emits = EmitsChangedSignal::False
}; self
}
/// Builder method that adds an annotation to the method. pubfn annotate<N: Into<String>, V: Into<String>>(mutself, name: N, value: V) -> Self { self.anns.insert(name, value); self
}
/// Builder method that adds an annotation that this entity is deprecated. pubfn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
/// Get property name pubfn get_name(&self) -> &str { &self.name }
/// Get associated data pubfn get_data(&self) -> &D::Property { &self.data }
/// Returns Ok if the property is gettable pubfn can_get(&self) -> Result<(), MethodErr> { ifself.rw == Access::Write || self.get_cb.is_none() {
Err(MethodErr::failed(&format!("Property {} is write only", &='color:red'>self.name)))
} else { Ok(()) }
}
/// Calls the on_get function and appends the result as a variant. /// /// Note: Will panic if get_cb is not set. pubfn get_as_variant(&self, i: &mut arg::IterAppend, pinfo: &PropInfo<M, D>) -> Result<(), MethodErr> { letmut r = Ok(());
i.append_variant(&self.sig, |subi| {
r = M::call_getprop(&*self.get_cb.as_ref().unwrap().0, subi, pinfo);
});
r
}
/// Returns Ok if the property is settable. /// /// Will verify signature in case iter is not None; iter is supposed to point at the Variant with the item inside. pubfn can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr> { use arg::Arg; ifself.rw == Access::Read || self.set_cb.is_none() || self.emits == EmitsChangedSignal::Const { return Err(MethodErr::ro_property(&self.name))
} iflet Some(mut i) = i { letmut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2))); if &*subiter.signature() != &*self.sig { return Err(MethodErr::failed(&format!("Property {} cannot change type", &self.name)))
}
}
Ok(())
}
/// Calls the on_set function, which reads from i. /// /// The return value might contain an extra message containing the EmitsChanged signal. /// Note: Will panic if set_cb is not set. pubfn set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> { use arg::Arg; letmut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2))); try!(M::call_setprop(&*self.set_cb.as_ref().unwrap().0, & style='color:red'>mut subiter, pinfo)); self.get_emits_changed_signal(pinfo)
}
/// Gets the signal (if any) associated with the Property. fn get_signal(&self, p: &PropInfo<M, D>) -> Message {
Message::signal(p.path.get_name(), &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
.append1(&**p.iface.get_name())
}
/// Adds this property to a list of PropertiesChanged signals. /// /// "v" is updated with the signal for this property. "new_value" is only called if self.emits is "true", /// it should return the value of the property. /// If no PropertiesChanged signal should be emitted for this property, "v" is left unchanged. pubfn add_propertieschanged<F: FnOnce() -> Box<arg::RefArg>>(&self, v: &mut Vec<PropertiesPropertiesChanged>, iface: &IfaceName, new_value: F) {
// Impl note: It is a bit silly that this function cannot be used from e g get_emits_changed_signal below, // but it is due to the fact that we cannot create a RefArg out of an IterAppend; which is what the 'on_get' // handler currently receives.
#[test] fn test_prop_handlers() { use tree::Factory; use std::collections::BTreeMap; use arg::{Dict, Variant};
#[derive(Default, Debug)] struct Custom; impl DataType for Custom { type Tree = (); type ObjectPath = (); type Interface = (); type Property = i32; type Method = (); type Signal = ();
}
let f = Factory::new_fn::<Custom>(); let tree = f.tree(()).add(f.object_path("/test", ()).introspectable().object_manager()
.add(f.interface("com.example.test", ())
.add_p(f.property::<i32,_>("Value1", 5i32).default_get())
.add_p(f.property::<i32,_>("Value2", 9i32).default_get())
)
);
letmut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Get").unwrap()
.append2("com.example.test", "Value1");
::message::message_set_serial(&mut msg, 4); let res = tree.handle(&msg).unwrap();
assert_eq!(res[0].get1(), Some(arg::Variant(5i32)));
letmut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "GetAll").unwrap()
.append1("com.example.test");
::message::message_set_serial(&mut msg, 4); let res = tree.handle(&msg).unwrap(); let d: Dict<&str, Variant<i32>, _> = res[0].get1().unwrap(); let z2: BTreeMap<_, _> = d.collect();
assert_eq!(z2.get("Value1"), Some(&arg::Variant(5i32)));
assert_eq!(z2.get("Value2"), Some(&arg::Variant(9i32)));
assert_eq!(z2.get("Mooh"), None);
letmut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects").unwrap();
::message::message_set_serial(&mut msg, 4); let res = tree.handle(&msg).unwrap(); let pdict: arg::Dict<Path, Dict<&str, Dict<&str, Variant<i32>, _>, _>, _> = res[0].get1().unwrap(); let pmap: BTreeMap<_, _> = pdict.collect(); let idict = pmap.get(&Path::from("/test")).unwrap(); let imap: BTreeMap<_, _> = idict.collect(); let propdict = imap.get("com.example.test").unwrap(); let propmap: BTreeMap<_, _> = propdict.collect();
assert_eq!(propmap.get("Value1"), Some(&arg::Variant(5i32)));
assert_eq!(propmap.get("Value2"), Some(&arg::Variant(9i32)));
assert_eq!(propmap.get("Mooh"), None);
}
#[test] fn test_set_prop() { use tree::{Factory, Access}; use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; use std::rc::Rc;
let changes = Rc::new(Cell::new(0i32)); let (changes1, changes2) = (changes.clone(), changes.clone()); let setme = Rc::new(RefCell::new("I have not been set yet!".to_owned())); let (setme1, setme2) = (setme.clone(), setme.clone());
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.