summaryrefslogtreecommitdiffstats
path: root/third_party/rust/dbus/src/tree
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/dbus/src/tree
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/dbus/src/tree')
-rw-r--r--third_party/rust/dbus/src/tree/factory.rs137
-rw-r--r--third_party/rust/dbus/src/tree/leaves.rs653
-rw-r--r--third_party/rust/dbus/src/tree/methodtype.rs275
-rw-r--r--third_party/rust/dbus/src/tree/mod.rs35
-rw-r--r--third_party/rust/dbus/src/tree/objectpath.rs553
-rw-r--r--third_party/rust/dbus/src/tree/utils.rs100
6 files changed, 1753 insertions, 0 deletions
diff --git a/third_party/rust/dbus/src/tree/factory.rs b/third_party/rust/dbus/src/tree/factory.rs
new file mode 100644
index 0000000000..2157fc4110
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/factory.rs
@@ -0,0 +1,137 @@
+use super::{MethodType, DataType, MTFn, MTFnMut, MTSync, MethodResult, MethodInfo};
+use super::{Tree, ObjectPath, Interface, Property, Signal, Method};
+use super::objectpath::IfaceCache;
+use std::sync::Arc;
+use Interface as IfaceName;
+use {Member, Path, arg};
+use std::cell::RefCell;
+
+/// The factory is used to create object paths, interfaces, methods etc.
+///
+/// There are three factories:
+///
+/// **MTFn** - all methods are `Fn()`.
+///
+/// **MTFnMut** - 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.
+///
+/// **MTSync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods
+/// can be called from different threads in parallel.
+///
+#[derive(Debug, Clone)]
+pub struct Factory<M: MethodType<D>, D: DataType=()>(Arc<IfaceCache<M, D>>);
+
+impl<M: MethodType<D>, D: DataType> From<Arc<IfaceCache<M, D>>> for Factory<M, D> {
+ fn from(f: Arc<IfaceCache<M, D>>) -> Self { Factory(f) }
+}
+
+impl Factory<MTFn<()>, ()> {
+ /// Creates a new factory for single-thread use.
+ pub fn new_fn<D: DataType>() -> Factory<MTFn<D>, D> { Factory(IfaceCache::new()) }
+
+ /// Creates a new factory for single-thread use, where callbacks can mutate their environment.
+ pub fn new_fnmut<D: DataType>() -> Factory<MTFnMut<D>, D> { Factory(IfaceCache::new()) }
+
+ /// Creates a new factory for multi-thread use.
+ pub fn new_sync<D: DataType>() -> Factory<MTSync<D>, D> { Factory(IfaceCache::new()) }
+
+}
+
+impl<D: DataType> Factory<MTFn<D>, D> {
+ /// Creates a new method for single-thread use.
+ pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFn<D>, D>
+ where H: 'static + Fn(&MethodInfo<MTFn<D>, D>) -> MethodResult, T: Into<Member<'static>> {
+ super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
+ }
+}
+
+impl<D: DataType> Factory<MTFnMut<D>, D> {
+ /// Creates a new method for single-thread use.
+ pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFnMut<D>, D>
+ where H: 'static + FnMut(&MethodInfo<MTFnMut<D>, D>) -> MethodResult, T: Into<Member<'static>> {
+ super::leaves::new_method(t.into(), data, Box::new(RefCell::new(handler)) as Box<_>)
+ }
+}
+
+impl<D: DataType> Factory<MTSync<D>, D> {
+ /// Creates a new method for multi-thread use.
+ pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTSync<D>, D>
+ where H: Fn(&MethodInfo<MTSync<D>, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
+ super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
+ }
+}
+
+
+impl<M: MethodType<D>, D: DataType> Factory<M, D> {
+
+ /// Creates a new property.
+ ///
+ /// `A` is used to calculate the type signature of the property.
+ pub fn property<A: arg::Arg, T: Into<String>>(&self, name: T, data: D::Property) -> Property<M, D> {
+ let sig = A::signature();
+ super::leaves::new_property(name.into(), sig, data)
+ }
+
+ /// Creates a new signal.
+ pub fn signal<T: Into<Member<'static>>>(&self, name: T, data: D::Signal) -> Signal<D> {
+ super::leaves::new_signal(name.into(), data)
+ }
+
+ /// Creates a new interface.
+ pub fn interface<T: Into<IfaceName<'static>>>(&self, name: T, data: D::Interface) -> Interface<M, D> {
+ super::objectpath::new_interface(name.into(), data)
+ }
+
+ /// Creates a new object path.
+ pub fn object_path<T: Into<Path<'static>>>(&self, name: T, data: D::ObjectPath) -> ObjectPath<M, D> {
+ super::objectpath::new_objectpath(name.into(), data, self.0.clone())
+ }
+
+ /// Creates a new tree.
+ pub fn tree(&self, data: D::Tree) -> Tree<M, D> {
+ super::objectpath::new_tree(data)
+ }
+
+ /// Creates a new method - usually you'll use "method" instead.
+ ///
+ /// This is useful for being able to create methods in code which is generic over methodtype.
+ pub fn method_sync<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<M, D>
+ where H: Fn(&MethodInfo<M, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
+ super::leaves::new_method(t.into(), data, M::make_method(handler))
+ }
+}
+
+
+#[test]
+fn create_fnmut() {
+ let f = Factory::new_fnmut::<()>();
+ let mut move_me = 5u32;
+ let m = f.method("test", (), move |m| {
+ move_me += 1;
+ Ok(vec!(m.msg.method_return().append1(&move_me)))
+ });
+ assert_eq!(&**m.get_name(), "test");
+}
+
+
+#[test]
+fn fn_customdata() {
+ #[derive(Default)]
+ struct Custom;
+ impl DataType for Custom {
+ type Tree = ();
+ type ObjectPath = Arc<u8>;
+ type Interface = ();
+ type Property = ();
+ type Method = i32;
+ type Signal = ();
+ }
+
+ let f = Factory::new_fn::<Custom>();
+
+ let m = f.method("test", 789, |_| unimplemented!());
+ assert_eq!(*m.get_data(), 789);
+
+ let o = f.object_path("/test/test", Arc::new(7));
+ assert_eq!(**o.get_data(), 7);
+}
diff --git a/third_party/rust/dbus/src/tree/leaves.rs b/third_party/rust/dbus/src/tree/leaves.rs
new file mode 100644
index 0000000000..3d358f7e0c
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/leaves.rs
@@ -0,0 +1,653 @@
+// Methods, signals, properties, and interfaces.
+use super::utils::{Argument, Annotations, Introspect, introspect_args};
+use super::{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;
+
+
+// Workaround for https://github.com/rust-lang/rust/issues/31518
+struct DebugMethod<M: MethodType<D>, D: DataType>(Box<M::Method>);
+impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugMethod<M, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Method>") }
+}
+struct DebugGetProp<M: MethodType<D>, D: DataType>(Box<M::GetProp>);
+impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugGetProp<M, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<GetProp>") }
+}
+struct DebugSetProp<M: MethodType<D>, D: DataType>(Box<M::SetProp>);
+impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugSetProp<M, D> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<SetProp>") }
+}
+
+
+#[derive(Debug)]
+/// A D-Bus Method.
+pub struct Method<M: MethodType<D>, D: DataType> {
+ cb: DebugMethod<M, D>,
+ data: D::Method,
+ name: Member<'static>,
+ i_args: Vec<Argument>,
+ o_args: Vec<Argument>,
+ anns: Annotations,
+}
+
+impl<M: MethodType<D>, D: DataType> Method<M, D> {
+
+ /// Builder method that adds an "in" Argument to this Method.
+ pub fn in_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.i_args.push(a.into()); self }
+ /// Builder method that adds an "in" Argument to this Method.
+ pub fn inarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.i_args.push((s.into(), A::signature()).into()); self }
+ /// Builder method that adds multiple "in" Arguments to this Method.
+ pub fn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, 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.
+ pub fn out_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.o_args.push(a.into()); self }
+ /// Builder method that adds an "out" Argument to this Method.
+ pub fn outarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.o_args.push((s.into(), A::signature()).into()); self }
+ /// Builder method that adds multiple "out" Arguments to this Method.
+ pub fn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
+ self.o_args.extend(a.into_iter().map(|b| b.into())); self
+ }
+
+ /// Builder method that adds an annotation to the method.
+ pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
+ self.anns.insert(name, value); self
+ }
+ /// Builder method that adds an annotation that this entity is deprecated.
+ pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
+
+ /// Call the Method
+ pub fn call(&self, minfo: &MethodInfo<M, D>) -> MethodResult { M::call_method(&self.cb.0, minfo) }
+
+ /// Get method name
+ pub fn get_name(&self) -> &Member<'static> { &self.name }
+
+ /// Get associated data
+ pub fn get_data(&self) -> &D::Method { &self.data }
+
+}
+
+impl<M: MethodType<D>, D: DataType> Introspect for Method<M, D> {
+ fn xml_name(&self) -> &'static str { "method" }
+ fn xml_params(&self) -> String { String::new() }
+ fn xml_contents(&self) -> String {
+ format!("{}{}{}",
+ introspect_args(&self.i_args, " ", " direction=\"in\""),
+ introspect_args(&self.o_args, " ", " direction=\"out\""),
+ self.anns.introspect(" "))
+ }
+}
+
+pub fn new_method<M: MethodType<D>, D: DataType>(n: Member<'static>, data: D::Method, cb: Box<M::Method>) -> Method<M, D> {
+ Method { name: n, i_args: vec!(), o_args: vec!(), anns: Annotations::new(), cb: DebugMethod(cb), data: data }
+}
+
+
+
+#[derive(Debug)]
+/// A D-Bus Signal.
+pub struct Signal<D: DataType> {
+ name: Member<'static>,
+ data: D::Signal,
+ arguments: Vec<Argument>,
+ anns: Annotations,
+}
+
+impl<D: DataType> Signal<D> {
+
+ /// Builder method that adds an Argument to the Signal.
+ pub fn arg<A: Into<Argument>>(mut self, a: A) -> Self { self.arguments.push(a.into()); self }
+
+ /// Builder method that adds an Argument to the Signal.
+ pub fn sarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.arguments.push((s.into(), A::signature()).into()); self }
+
+ /// Builder method that adds multiple Arguments to the Signal.
+ pub fn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
+ self.arguments.extend(a.into_iter().map(|b| b.into())); self
+ }
+
+ /// Add an annotation to this Signal.
+ pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
+ self.anns.insert(name, value); self
+ }
+ /// Add an annotation that this entity is deprecated.
+ pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
+
+ /// Get signal name
+ pub fn get_name(&self) -> &Member<'static> { &self.name }
+
+ /// Get associated data
+ pub fn 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.
+ pub fn emit(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[MessageItem]) -> Message {
+ let mut 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.
+ pub fn msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message {
+ Message::signal(p, i, &self.name)
+ }
+
+}
+
+impl<D: DataType> Introspect for Signal<D> {
+ fn xml_name(&self) -> &'static str { "signal" }
+ fn xml_params(&self) -> String { String::new() }
+ fn xml_contents(&self) -> String {
+ format!("{}{}",
+ introspect_args(&self.arguments, " ", ""),
+ self.anns.introspect(" "))
+ }
+}
+
+pub fn 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.
+pub enum 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.
+pub enum 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 Access {
+ fn introspect(&self) -> &'static str {
+ match self {
+ &Access::Read => "read",
+ &Access::ReadWrite => "readwrite",
+ &Access::Write => "write",
+ }
+ }
+}
+
+
+pub fn prop_append_dict<'v, M: MethodType<D> + 'v, D: DataType + 'v, I: Iterator<Item=&'v Property<M, D>>>
+ (iter: &mut arg::IterAppend, mut props: I, minfo: &MethodInfo<M, D>) -> Result<(), MethodErr> {
+
+ let mut result = Ok(());
+ iter.append_dict(&Signature::make::<&str>(), &Signature::make::<arg::Variant<bool>>(), |subiter| loop {
+ let p = if let Some(p) = props.next() { p } else { return };
+ if p.can_get().is_err() { continue; }
+ let pinfo = minfo.to_prop_info(minfo.iface, p);
+ subiter.append_dict_entry(|mut entryiter| {
+ entryiter.append(&*p.get_name());
+ result = p.get_as_variant(&mut entryiter, &pinfo);
+ });
+ if result.is_err() { return };
+ });
+ result
+}
+
+
+#[derive(Debug)]
+/// A D-Bus Property.
+pub struct Property<M: MethodType<D>, D: DataType> {
+ name: String,
+ data: D::Property,
+ sig: Signature<'static>,
+ emits: EmitsChangedSignal,
+ auto_emit: bool,
+ rw: Access,
+ get_cb: Option<DebugGetProp<M, D>>,
+ set_cb: Option<DebugSetProp<M, D>>,
+ anns: Annotations,
+}
+
+impl<M: MethodType<D>, D: DataType> Property<M, D> {
+
+ /// 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.
+ pub fn emits_changed(mut self, e: EmitsChangedSignal) -> Self {
+ self.emits = e;
+ if self.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).
+ pub fn auto_emit_on_set(mut self, 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".
+ pub fn access(mut self, e: Access) -> Self {
+ self.rw = e;
+ if self.rw != Access::Read && self.emits == EmitsChangedSignal::Const {
+ self.emits = EmitsChangedSignal::False
+ };
+ self
+ }
+
+ /// Builder method that adds an annotation to the method.
+ pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
+ self.anns.insert(name, value); self
+ }
+
+ /// Builder method that adds an annotation that this entity is deprecated.
+ pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
+
+ /// Get property name
+ pub fn get_name(&self) -> &str { &self.name }
+
+ /// Get associated data
+ pub fn get_data(&self) -> &D::Property { &self.data }
+
+ /// Returns Ok if the property is gettable
+ pub fn can_get(&self) -> Result<(), MethodErr> {
+ if self.rw == Access::Write || self.get_cb.is_none() {
+ Err(MethodErr::failed(&format!("Property {} is write only", &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.
+ pub fn get_as_variant(&self, i: &mut arg::IterAppend, pinfo: &PropInfo<M, D>) -> Result<(), MethodErr> {
+ let mut 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.
+ pub fn can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr> {
+ use arg::Arg;
+ if self.rw == Access::Read || self.set_cb.is_none() || self.emits == EmitsChangedSignal::Const {
+ return Err(MethodErr::ro_property(&self.name))
+ }
+ if let Some(mut i) = i {
+ let mut 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.
+ pub fn set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
+ use arg::Arg;
+ let mut 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, &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.
+ pub fn 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.
+
+ if self.emits == EmitsChangedSignal::Const || self.emits == EmitsChangedSignal::False { return; }
+ let vpos = v.iter().position(|vv| &*vv.interface_name == &**iface);
+ let vpos = vpos.unwrap_or_else(|| {
+ let mut z: PropertiesPropertiesChanged = Default::default();
+ z.interface_name = (&**iface).into();
+ v.push(z);
+ v.len()-1
+ });
+
+ let vv = &mut v[vpos];
+ if self.emits == EmitsChangedSignal::Invalidates {
+ vv.invalidated_properties.push(self.name.clone());
+ } else {
+ vv.changed_properties.insert(self.name.clone(), arg::Variant(new_value()));
+ }
+ }
+
+ fn get_emits_changed_signal(&self, m: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
+ if !self.auto_emit { return Ok(None) }
+ match self.emits {
+ EmitsChangedSignal::False => Ok(None),
+ EmitsChangedSignal::Const => Err(MethodErr::ro_property(&self.name)),
+ EmitsChangedSignal::True => Ok(Some({
+ let mut s = self.get_signal(m);
+ {
+ let mut iter = arg::IterAppend::new(&mut s);
+ try!(prop_append_dict(&mut iter, Some(self).into_iter(), &m.to_method_info()));
+ iter.append(arg::Array::<&str, _>::new(vec!()));
+ }
+ s
+ })),
+ EmitsChangedSignal::Invalidates => Ok(Some(self.get_signal(m).append2(
+ arg::Dict::<&str, arg::Variant<bool>, _>::new(vec!()),
+ arg::Array::new(Some(&*self.name).into_iter())
+ ))),
+ }
+ }
+}
+
+impl<'a, D: DataType> Property<MTFn<D>, D> {
+ /// Sets the callback for getting a property.
+ ///
+ /// For single-thread use.
+ pub fn on_get<H>(mut self, handler: H) -> Property<MTFn<D>, D>
+ where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
+ self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
+ self
+ }
+
+ /// Sets the callback for setting a property.
+ ///
+ /// For single-thread use.
+ pub fn on_set<H>(mut self, handler: H) -> Property<MTFn<D>, D>
+ where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
+ self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
+ self
+ }
+}
+
+
+impl<'a, D: DataType> Property<MTFnMut<D>, D> {
+ /// Sets the callback for getting a property.
+ ///
+ /// For single-thread use.
+ pub fn on_get<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
+ where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
+ self.get_cb = Some(DebugGetProp(Box::new(RefCell::new(handler)) as Box<_>));
+ self
+ }
+
+ /// Sets the callback for setting a property.
+ ///
+ /// For single-thread use.
+ pub fn on_set<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
+ where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
+ self.set_cb = Some(DebugSetProp(Box::new(RefCell::new(handler)) as Box<_>));
+ self
+ }
+}
+
+impl<D: DataType> Property<MTSync<D>, D> {
+ /// Sets the callback for getting a property.
+ ///
+ /// For multi-thread use.
+ pub fn on_get<H>(mut self, handler: H) -> Property<MTSync<D>, D>
+ where H: Fn(&mut arg::IterAppend, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
+ self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
+ self
+ }
+
+ /// Sets the callback for setting a property.
+ ///
+ /// For single-thread use.
+ pub fn on_set<H>(mut self, handler: H) -> Property<MTSync<D>, D>
+ where H: Fn(&mut arg::Iter, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
+ self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
+ self
+ }
+}
+
+
+impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::Append + Clone {
+ /// Adds a "standard" get handler.
+ pub fn default_get(mut self) -> Self {
+ let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { i.append(p.prop.get_data()); Ok(()) };
+ self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
+ self
+ }
+}
+
+
+impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::RefArg {
+ /// Adds a "standard" get handler (for RefArgs).
+ pub fn default_get_refarg(mut self) -> Self {
+ let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { (p.prop.get_data() as &arg::RefArg).append(i); Ok(()) };
+ self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
+ self
+ }
+}
+
+impl<M: MethodType<D>, D: DataType> Introspect for Property<M, D> {
+ fn xml_name(&self) -> &'static str { "property" }
+ fn xml_params(&self) -> String { format!(" type=\"{}\" access=\"{}\"", self.sig, self.rw.introspect()) }
+ fn xml_contents(&self) -> String {
+ let s = match self.emits {
+ EmitsChangedSignal::True => return self.anns.introspect(" "),
+ EmitsChangedSignal::False => "false",
+ EmitsChangedSignal::Const => "const",
+ EmitsChangedSignal::Invalidates => "invalidates",
+ };
+ let mut tempanns = self.anns.clone();
+ tempanns.insert("org.freedesktop.DBus.Property.EmitsChangedSignal", s);
+ tempanns.introspect(" ")
+ }
+}
+
+pub fn new_property<M: MethodType<D>, D: DataType>
+ (n: String, sig: Signature<'static>, data: D::Property) -> Property<M, D> {
+ Property {
+ name: n, emits: EmitsChangedSignal::True, auto_emit: true, rw: Access::Read,
+ sig: sig, anns: Annotations::new(), set_cb: None, get_cb: None, data: data
+ }
+}
+
+#[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())
+ )
+ );
+
+ let mut 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)));
+
+ let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append3("com.example.test", "Value1", arg::Variant(3i32));
+ ::message::message_set_serial(&mut msg, 4);
+ let mut res = tree.handle(&msg).unwrap();
+ assert!(res[0].as_result().is_err());
+
+ let mut 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);
+
+ let mut 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());
+
+ let f = Factory::new_fn::<()>();
+ let tree = f.tree(()).add(f.object_path("/example", ()).introspectable()
+ .add(f.interface("com.example.dbus.rs", ())
+ .add_p(f.property::<i32,_>("changes", ())
+ .on_get(move |i, _| { i.append(changes1.get()); Ok(()) }))
+ .add_p(f.property::<String,_>("setme", ())
+ .access(Access::ReadWrite)
+ .on_get(move |i, _| { i.append(&*setme1.borrow()); Ok(()) })
+ .on_set(move |i, _| {
+ *setme2.borrow_mut() = i.get().unwrap();
+ changes2.set(changes2.get() + 1);
+ Ok(())
+ }))
+ )
+ );
+
+ // Read-only
+ let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append3("com.example.dbus.rs", "changes", arg::Variant(5i32));
+ ::message::message_set_serial(&mut msg, 20);
+ let mut r = tree.handle(&msg).unwrap();
+ assert!(r.get_mut(0).unwrap().as_result().is_err());
+
+ // Wrong type
+ let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append3("com.example.dbus.rs", "setme", arg::Variant(8i32));
+ ::message::message_set_serial(&mut msg, 30);
+ let mut r = tree.handle(&msg).unwrap();
+ assert!(r.get_mut(0).unwrap().as_result().is_err());
+
+ // Correct!
+ let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append3("com.example.dbus.rs", "setme", arg::Variant("Correct"));
+ ::message::message_set_serial(&mut msg, 30);
+ let r = tree.handle(&msg).unwrap();
+
+ assert_eq!(changes.get(), 1);
+ assert_eq!(&**setme.borrow(), "Correct");
+
+ println!("{:?}", r);
+ assert_eq!(r.len(), 2);
+ assert_eq!(&*r[0].member().unwrap(), "PropertiesChanged");
+ let (s, d): (Option<&str>, Option<arg::Dict<&str, arg::Variant<_>, _>>) = r[0].get2();
+ assert_eq!(s, Some("com.example.dbus.rs"));
+ let z2: BTreeMap<_, _> = d.unwrap().collect();
+ assert_eq!(z2.get("setme"), Some(&arg::Variant("Correct")));
+
+}
+
+
+#[test]
+fn test_sync_prop() {
+ use std::sync::atomic::{AtomicUsize, Ordering};
+ use std::sync::Arc;
+ use tree::{Factory, Access, EmitsChangedSignal};
+
+ let f = Factory::new_sync::<()>();
+
+ let count = Arc::new(AtomicUsize::new(3));
+ let (cget, cset) = (count.clone(), count.clone());
+
+ let tree1 = Arc::new(f.tree(()).add(f.object_path("/syncprop", ()).introspectable()
+ .add(f.interface("com.example.syncprop", ())
+ .add_p(f.property::<u32,_>("syncprop", ())
+ .access(Access::ReadWrite)
+ .emits_changed(EmitsChangedSignal::False)
+ .on_get(move |i,_| { i.append(cget.load(Ordering::SeqCst) as u32); Ok(()) })
+ .on_set(move |i,_| { cset.store(i.get::<u32>().unwrap() as usize, Ordering::SeqCst); Ok(()) })
+ )
+ )
+ ));
+
+ let tree2 = tree1.clone();
+ println!("{:#?}", tree2);
+
+ ::std::thread::spawn(move || {
+ let mut msg = Message::new_method_call("com.example.syncprop", "/syncprop", "org.freedesktop.DBus.Properties", "Set").unwrap()
+ .append3("com.example.syncprop", "syncprop", arg::Variant(5u32));
+ ::message::message_set_serial(&mut msg, 30);
+ let mut r = tree2.handle(&msg).unwrap();
+ assert!(r[0].as_result().is_ok());
+ });
+
+ loop {
+ let mut msg = Message::new_method_call("com.example.echoserver", "/syncprop", "org.freedesktop.DBus.Properties", "Get").unwrap()
+ .append("com.example.syncprop").append1("syncprop");
+ ::message::message_set_serial(&mut msg, 4);
+ let mut r = tree1.handle(&msg).unwrap();
+ let r = r[0].as_result().unwrap();
+ let z: arg::Variant<u32> = r.get1().unwrap();
+ if z.0 == 5 { break; }
+ assert_eq!(z.0, 3);
+ }
+ assert_eq!(count.load(Ordering::SeqCst), 5);
+}
diff --git a/third_party/rust/dbus/src/tree/methodtype.rs b/third_party/rust/dbus/src/tree/methodtype.rs
new file mode 100644
index 0000000000..38b0669d77
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/methodtype.rs
@@ -0,0 +1,275 @@
+// Methods and method types. Glue to make stuff generic over MFn, MFnMut and MSync
+
+use std::fmt;
+use {ErrorName, Message, stdintf};
+use arg::{Iter, IterAppend, TypeMismatchError};
+use std::marker::PhantomData;
+use super::{Method, Interface, Property, ObjectPath, Tree};
+use std::cell::RefCell;
+use std::ffi::CString;
+use super::super::Error as dbusError;
+
+#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+/// A D-Bus Method Error, containing an error name and a description.
+pub struct MethodErr(ErrorName<'static>, String);
+
+impl MethodErr {
+ /// Create an Invalid Args MethodErr.
+ pub fn invalid_arg<T: fmt::Debug>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.InvalidArgs", format!("Invalid argument {:?}", a)).into()
+ }
+ /// Create a MethodErr that there are not enough arguments given.
+ pub fn no_arg() -> MethodErr {
+ ("org.freedesktop.DBus.Error.InvalidArgs", "Not enough arguments").into()
+ }
+ /// Create a MethodErr that the method failed in the way specified.
+ pub fn failed<T: fmt::Display>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.Failed", a.to_string()).into()
+ }
+ /// Create a MethodErr that the Interface was unknown.
+ pub fn no_interface<T: fmt::Display>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.UnknownInterface", format!("Unknown interface {}", a)).into()
+ }
+ /// Create a MethodErr that the Method was unknown.
+ pub fn no_method<T: fmt::Display>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.UnknownMethod", format!("Unknown method {}", a)).into()
+ }
+ /// Create a MethodErr that the Property was unknown.
+ pub fn no_property<T: fmt::Display>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.UnknownProperty", format!("Unknown property {}", a)).into()
+ }
+ /// Create a MethodErr that the Property was read-only.
+ pub fn ro_property<T: fmt::Display>(a: &T) -> MethodErr {
+ ("org.freedesktop.DBus.Error.PropertyReadOnly", format!("Property {} is read only", a)).into()
+ }
+
+ /// Error name accessor
+ pub fn errorname(&self) -> &ErrorName<'static> { &self.0 }
+ /// Description accessor
+ pub fn description(&self) -> &str { &self.1 }
+
+ /// Creates an error reply from a method call message.
+ ///
+ /// Note: You normally don't need to use this function,
+ /// as it is called internally from Tree::handle.
+ pub fn to_message(&self, msg: &Message) -> Message {
+ msg.error(&self.0, &CString::new(&*self.1).unwrap())
+ }
+}
+
+impl From<TypeMismatchError> for MethodErr {
+ fn from(t: TypeMismatchError) -> MethodErr { ("org.freedesktop.DBus.Error.Failed", format!("{}", t)).into() }
+}
+
+impl<T: Into<ErrorName<'static>>, M: Into<String>> From<(T, M)> for MethodErr {
+ fn from((t, m): (T, M)) -> MethodErr { MethodErr(t.into(), m.into()) }
+}
+
+impl From<dbusError> for MethodErr {
+ fn from(t: dbusError) -> MethodErr {
+ let n = t.name().unwrap_or("org.freedesktop.DBus.Error.Failed");
+ let m = t.message().unwrap_or("Unknown error");
+ MethodErr(String::from(n).into(), m.into())
+ }
+}
+
+
+/// Result containing the Messages returned from the Method, or a MethodErr.
+pub type MethodResult = Result<Vec<Message>, MethodErr>;
+
+/// Associated data for different objects in a tree.
+///
+/// These currently require a debug bound, due to https://github.com/rust-lang/rust/issues/31518
+pub trait DataType: Sized + Default {
+ /// Type of associated data on the Tree.
+ type Tree: fmt::Debug;
+ /// Type of associated data on every ObjectPath.
+ type ObjectPath: fmt::Debug;
+ /// Type of associated data on every Property.
+ type Property: fmt::Debug;
+ /// Type of associated data on every Interface.
+ type Interface: fmt::Debug;
+ /// Type of associated data on every Method.
+ type Method: fmt::Debug;
+ /// Type of associated data on every Signal.
+ type Signal: fmt::Debug;
+}
+
+/// No associated data for the tree.
+impl DataType for () {
+ type Tree = ();
+ type ObjectPath = ();
+ type Interface = ();
+ type Property = ();
+ type Method = ();
+ type Signal = ();
+}
+
+/// A helper trait used internally to make the tree generic over MTFn, MTFnMut and MTSync.
+///
+/// You should not need to call these methods directly, it's primarily for internal use.
+pub trait MethodType<D: DataType>: Sized + Default {
+ /// For internal use.
+ type Method: ?Sized;
+ /// For internal use.
+ type GetProp: ?Sized;
+ /// For internal use.
+ type SetProp: ?Sized;
+
+ /// For internal use.
+ fn call_getprop(&Self::GetProp, &mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>;
+ /// For internal use.
+ fn call_setprop(&Self::SetProp, &mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>;
+ /// For internal use.
+ fn call_method(&Self::Method, &MethodInfo<Self, D>) -> MethodResult;
+
+ /// For internal use.
+ fn make_getprop<H>(h: H) -> Box<Self::GetProp>
+ where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static;
+ /// For internal use.
+ fn make_method<H>(h: H) -> Box<Self::Method>
+ where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static;
+}
+
+
+/// An abstract type to represent Fn functions.
+#[derive(Default, Debug, Copy, Clone)]
+pub struct MTFn<D=()>(PhantomData<*const D>);
+
+impl<D: DataType> MethodType<D> for MTFn<D> {
+ type GetProp = Fn(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>;
+ type SetProp = Fn(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>;
+ type Method = Fn(&MethodInfo<Self, D>) -> MethodResult;
+
+ fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { p(i, pinfo) }
+ fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { p(i, pinfo) }
+ fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
+ -> MethodResult { p(minfo) }
+
+ fn make_getprop<H>(h: H) -> Box<Self::GetProp>
+ where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(h) }
+ fn make_method<H>(h: H) -> Box<Self::Method>
+ where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(h) }
+}
+
+/// An abstract type to represent FnMut functions.
+#[derive(Default, Debug, Copy, Clone)]
+pub struct MTFnMut<D=()>(PhantomData<*const D>);
+
+impl<D: DataType> MethodType<D> for MTFnMut<D> {
+ type GetProp = RefCell<FnMut(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr>>;
+ type SetProp = RefCell<FnMut(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr>>;
+ type Method = RefCell<FnMut(&MethodInfo<Self, D>) -> MethodResult>;
+
+ fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { (&mut *p.borrow_mut())(i, pinfo) }
+ fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { (&mut *p.borrow_mut())(i, pinfo) }
+ fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
+ -> MethodResult { (&mut *p.borrow_mut())(minfo) }
+
+ fn make_getprop<H>(h: H) -> Box<Self::GetProp>
+ where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(RefCell::new(h)) }
+ fn make_method<H>(h: H) -> Box<Self::Method>
+ where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(RefCell::new(h)) }
+
+}
+
+/// An abstract type to represent Fn + Send + Sync functions (that can be called from several threads in parallel).
+#[derive(Default, Debug, Copy, Clone)]
+pub struct MTSync<D=()>(PhantomData<*const D>);
+
+impl<D: DataType> MethodType<D> for MTSync<D> {
+ type GetProp = Fn(&mut IterAppend, &PropInfo<Self, D>) -> Result<(), MethodErr> + Send + Sync + 'static;
+ type SetProp = Fn(&mut Iter, &PropInfo<Self, D>) -> Result<(), MethodErr> + Send + Sync + 'static;
+ type Method = Fn(&MethodInfo<Self, D>) -> MethodResult + Send + Sync + 'static;
+
+ fn call_getprop(p: &Self::GetProp, i: &mut IterAppend, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { p(i, pinfo) }
+ fn call_setprop(p: &Self::SetProp, i: &mut Iter, pinfo: &PropInfo<Self, D>)
+ -> Result<(), MethodErr> { p(i, pinfo) }
+ fn call_method(p: &Self::Method, minfo: &MethodInfo<Self, D>)
+ -> MethodResult { p(minfo) }
+
+ fn make_getprop<H>(h: H) -> Box<Self::GetProp>
+ where H: Fn(&mut IterAppend, &PropInfo<Self,D>) -> Result<(), MethodErr> + Send + Sync + 'static { Box::new(h) }
+ fn make_method<H>(h: H) -> Box<Self::Method>
+ where H: Fn(&MethodInfo<Self,D>) -> MethodResult + Send + Sync + 'static { Box::new(h) }
+}
+
+
+
+#[derive(Debug, Copy, Clone)]
+/// Contains information about the incoming method call.
+pub struct MethodInfo<'a, M: 'a + MethodType<D>, D: 'a + DataType> {
+ /// Message
+ pub msg: &'a Message,
+ /// The method to be called
+ pub method: &'a Method<M, D>,
+ /// Interface
+ pub iface: &'a Interface<M, D>,
+ /// Object path
+ pub path: &'a ObjectPath<M, D>,
+ /// Tree
+ pub tree: &'a Tree<M, D>,
+}
+
+impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> MethodInfo<'a, M, D> {
+ /// MethodInfo to PropInfo conversion
+ pub fn to_prop_info(&self, iface: &'a Interface<M, D>, prop: &'a Property<M, D>) -> PropInfo<'a, M, D> {
+ PropInfo { msg: self.msg, method: self.method, iface: iface, prop: prop, path: self.path, tree: self.tree }
+ }
+}
+
+
+impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> stdintf::OrgFreedesktopDBusIntrospectable for MethodInfo<'a, M, D> {
+ type Err = MethodErr;
+ fn introspect(&self) -> Result<String, Self::Err> { Ok(self.path.introspect(self.tree)) }
+}
+
+// Mostly autogenerated by dbus-codegen
+pub fn org_freedesktop_dbus_introspectable_server<M, D>(factory: &super::Factory<M, D>, data: D::Interface) -> super::Interface<M, D>
+where
+ D: super::DataType,
+ D::Method: Default,
+ M: MethodType<D>,
+{
+ let i = factory.interface("org.freedesktop.DBus.Introspectable", data);
+ let h = move |minfo: &super::MethodInfo<M, D>| {
+ let d: &stdintf::OrgFreedesktopDBusIntrospectable<Err=super::MethodErr> = minfo;
+ let arg0 = try!(d.introspect());
+ let rm = minfo.msg.method_return();
+ let rm = rm.append1(arg0);
+ Ok(vec!(rm))
+ };
+ let m = factory.method_sync("Introspect", Default::default(), h);
+ let m = m.out_arg(("xml_data", "s"));
+ let i = i.add_m(m);
+ i
+}
+
+#[derive(Debug, Copy, Clone)]
+/// Contains information about the incoming property get/set request.
+pub struct PropInfo<'a, M: 'a + MethodType<D>, D: 'a + DataType> {
+ /// Message
+ pub msg: &'a Message,
+ /// Get, Set or GetAll
+ pub method: &'a Method<M, D>,
+ /// The property to be set/get
+ pub prop: &'a Property<M, D>,
+ /// The interface the property belongs to
+ pub iface: &'a Interface<M, D>,
+ /// Object path
+ pub path: &'a ObjectPath<M, D>,
+ /// Tree
+ pub tree: &'a Tree<M, D>,
+}
+
+impl<'a, M: 'a + MethodType<D>, D: 'a + DataType> PropInfo<'a, M, D> {
+ /// PropInfo to MethodInfo conversion.
+ pub fn to_method_info(&self) -> MethodInfo<'a, M, D> {
+ MethodInfo { msg: self.msg, method: self.method, iface: self.iface, path: self.path, tree: self.tree }
+ }
+}
diff --git a/third_party/rust/dbus/src/tree/mod.rs b/third_party/rust/dbus/src/tree/mod.rs
new file mode 100644
index 0000000000..00257235fb
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/mod.rs
@@ -0,0 +1,35 @@
+//! Contains functionality for dispatching methods on a D-Bus "server".
+//!
+//! # Example
+//! ```rust,no_run
+//! use dbus::{tree, Connection, BusType};
+//! let f = tree::Factory::new_fn::<()>();
+//! /* Add a method returning "Thanks!" on interface "com.example.dbus.rs"
+//! on object path "/example". */
+//! let t = f.tree(()).add(f.object_path("/example", ()).introspectable()
+//! .add(f.interface("com.example.dbus.rs", ())
+//! .add_m(f.method("CallMe", (), |m| {
+//! Ok(vec!(m.msg.method_return().append("Thanks!"))) }
+//! ).out_arg("s"))
+//! ));
+//!
+//! let c = Connection::get_private(BusType::Session).unwrap();
+//! t.set_registered(&c, true).unwrap();
+//! c.add_handler(t);
+//! /* Run forever */
+//! loop { c.incoming(1000).next(); }
+//! ```
+//!
+//! See `examples/server.rs` and `examples/adv_server.rs` for more thorough examples.
+
+mod utils;
+mod methodtype;
+mod leaves;
+mod objectpath;
+mod factory;
+
+pub use self::utils::{Argument, Iter};
+pub use self::methodtype::{MethodErr, MethodInfo, PropInfo, MethodResult, MethodType, DataType, MTFn, MTFnMut, MTSync};
+pub use self::leaves::{Method, Signal, Property, Access, EmitsChangedSignal};
+pub use self::objectpath::{Interface, ObjectPath, Tree, TreeServer};
+pub use self::factory::Factory;
diff --git a/third_party/rust/dbus/src/tree/objectpath.rs b/third_party/rust/dbus/src/tree/objectpath.rs
new file mode 100644
index 0000000000..cc2fb0ba05
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/objectpath.rs
@@ -0,0 +1,553 @@
+use super::utils::{ArcMap, Iter, IterE, Annotations, Introspect};
+use super::{Factory, MethodType, MethodInfo, MethodResult, MethodErr, DataType, Property, Method, Signal, methodtype};
+use std::sync::{Arc, Mutex};
+use {Member, Message, Path, Signature, MessageType, Connection, ConnectionItem, Error, arg, MsgHandler, MsgHandlerType, MsgHandlerResult};
+use Interface as IfaceName;
+use std::fmt;
+use std::ffi::CStr;
+use super::leaves::prop_append_dict;
+
+fn introspect_map<I: fmt::Display, T: Introspect>
+ (h: &ArcMap<I, T>, indent: &str) -> String {
+
+ h.iter().fold("".into(), |a, (k, v)| {
+ let (name, params, contents) = (v.xml_name(), v.xml_params(), v.xml_contents());
+ format!("{}{}<{} name=\"{}\"{}{}>\n",
+ a, indent, name, &*k, params, if contents.len() > 0 {
+ format!(">\n{}{}</{}", contents, indent, name)
+ }
+ else { format!("/") }
+ )
+ })
+}
+
+#[derive(Debug)]
+/// Represents a D-Bus interface.
+pub struct Interface<M: MethodType<D>, D: DataType> {
+ name: Arc<IfaceName<'static>>,
+ methods: ArcMap<Member<'static>, Method<M, D>>,
+ signals: ArcMap<Member<'static>, Signal<D>>,
+ properties: ArcMap<String, Property<M, D>>,
+ anns: Annotations,
+ data: D::Interface,
+}
+
+impl<M: MethodType<D>, D: DataType> Interface<M, D> {
+ /// Builder function that adds a method to the interface.
+ pub fn add_m<I: Into<Arc<Method<M, D>>>>(mut self, 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.
+ pub fn add_s<I: Into<Arc<Signal<D>>>>(mut self, 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.
+ pub fn add_p<I: Into<Arc<Property<M, D>>>>(mut self, 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.
+ pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
+ self.anns.insert(name, value); self
+ }
+
+ /// Builder function that adds an annotation that this entity is deprecated.
+ pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
+
+ /// Get interface name
+ pub fn get_name(&self) -> &IfaceName<'static> { &self.name }
+
+ /// Get associated data
+ pub fn get_data(&self) -> &D::Interface { &self.data }
+
+ /// Iterates over methods implemented by this interface.
+ pub fn iter_m<'a>(&'a self) -> Iter<'a, Method<M, D>> { IterE::Member(self.methods.values()).into() }
+
+ /// Iterates over signals implemented by this interface.
+ pub fn iter_s<'a>(&'a self) -> Iter<'a, Signal<D>> { IterE::Member(self.signals.values()).into() }
+
+ /// Iterates over properties implemented by this interface.
+ pub fn iter_p<'a>(&'a self) -> Iter<'a, Property<M, D>> { IterE::String(self.properties.values()).into() }
+}
+
+impl<M: MethodType<D>, D: DataType> Introspect for Interface<M, D> {
+ fn xml_name(&self) -> &'static str { "interface" }
+ fn xml_params(&self) -> String { String::new() }
+ fn xml_contents(&self) -> String {
+ format!("{}{}{}{}",
+ introspect_map(&self.methods, " "),
+ introspect_map(&self.properties, " "),
+ introspect_map(&self.signals, " "),
+ self.anns.introspect(" "))
+ }
+}
+
+
+pub fn new_interface<M: MethodType<D>, D: DataType>(t: IfaceName<'static>, d: D::Interface) -> Interface<M, D> {
+ Interface { name: Arc::new(t), methods: ArcMap::new(), signals: ArcMap::new(),
+ properties: ArcMap::new(), anns: Annotations::new(), data: d
+ }
+}
+
+
+#[derive(Debug)]
+/// Cache of built-in interfaces, in order to save memory when many object paths implement the same interface(s).
+pub struct 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 {
+ pub fn 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();
+ let mut m = self.0.lock().unwrap();
+ m.entry(s2).or_insert_with(|| {
+ let i = new_interface(s.into(), Default::default());
+ Arc::new(f(i))
+ }).clone()
+ }
+}
+
+impl<M: MethodType<D>, D: DataType> IfaceCache<M, D> {
+ pub fn get_factory<S: Into<IfaceName<'static>> + Clone, F>(&self, s: S, f: F) -> Arc<Interface<M, D>>
+ where F: FnOnce() -> Interface<M, D> {
+ let s2 = s.clone().into();
+ let mut m = self.0.lock().unwrap();
+ m.entry(s2).or_insert_with(|| {
+ Arc::new(f())
+ }).clone()
+ }
+
+
+ pub fn new() -> Arc<Self> { Arc::new(IfaceCache(Mutex::new(ArcMap::new()))) }
+}
+
+#[derive(Debug)]
+/// A D-Bus Object Path.
+pub struct ObjectPath<M: MethodType<D>, D: DataType> {
+ name: Arc<Path<'static>>,
+ default_iface: Option<IfaceName<'static>>,
+ ifaces: ArcMap<Arc<IfaceName<'static>>, Interface<M, D>>,
+ ifacecache: Arc<IfaceCache<M, D>>,
+ data: D::ObjectPath,
+}
+
+impl<M: MethodType<D>, D: DataType> ObjectPath<M, D> {
+
+ /// Get property name
+ pub fn get_name(&self) -> &Path<'static> { &self.name }
+
+ /// Get associated data
+ pub fn get_data(&self) -> &D::ObjectPath { &self.data }
+
+ /// Iterates over interfaces implemented by this object path.
+ pub fn iter<'a>(&'a self) -> Iter<'a, Interface<M, D>> { IterE::Iface(self.ifaces.values()).into() }
+
+ pub(super) fn introspect(&self, tree: &Tree<M, D>) -> String {
+ let ifacestr = introspect_map(&self.ifaces, " ");
+ let olen = self.name.len()+1;
+ let childstr = tree.children(self, true).iter().fold("".to_string(), |na, n|
+ format!("{} <node name=\"{}\"/>\n", na, &n.name[olen..])
+ );
+
+ 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">
+<node name="{}">
+{}{}</node>"##, self.name, ifacestr, childstr);
+ nodestr
+ }
+
+ fn get_iface<'a>(&'a self, iface_name: &'a CStr) -> Result<&Arc<Interface<M, D>>, MethodErr> {
+ let j = try!(IfaceName::from_slice(iface_name.to_bytes_with_nul()).map_err(|e| MethodErr::invalid_arg(&e)));
+ self.ifaces.get(&j).ok_or_else(|| MethodErr::no_interface(&j))
+ }
+
+ fn prop_get(&self, m: &MethodInfo<M, D>) -> MethodResult {
+ let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
+ let iface = try!(self.get_iface(iname));
+ let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
+ .ok_or_else(|| MethodErr::no_property(&prop_name)));
+ try!(prop.can_get());
+ let mut mret = m.msg.method_return();
+ {
+ let mut iter = arg::IterAppend::new(&mut mret);
+ let pinfo = m.to_prop_info(iface, prop);
+ try!(prop.get_as_variant(&mut iter, &pinfo));
+ }
+ Ok(vec!(mret))
+ }
+
+ fn prop_get_all(&self, m: &MethodInfo<M, D>) -> MethodResult {
+ let iface = try!(self.get_iface(try!(m.msg.read1())));
+ let mut mret = m.msg.method_return();
+ try!(prop_append_dict(&mut arg::IterAppend::new(&mut mret),
+ iface.properties.values().map(|v| &**v), m));
+ Ok(vec!(mret))
+ }
+
+
+ fn prop_set(&self, m: &MethodInfo<M, D>) -> MethodResult {
+ let (iname, prop_name): (&CStr, &str) = try!(m.msg.read2());
+ let iface = try!(self.get_iface(iname));
+ let prop: &Property<M, D> = try!(iface.properties.get(&String::from(prop_name))
+ .ok_or_else(|| MethodErr::no_property(&prop_name)));
+
+ let mut iter = arg::Iter::new(m.msg);
+ iter.next(); iter.next();
+ let mut iter2 = iter;
+ try!(prop.can_set(Some(iter)));
+
+ let pinfo = m.to_prop_info(iface, prop);
+ let mut r: Vec<Message> = try!(prop.set_as_variant(&mut iter2, &pinfo)).into_iter().collect();
+ r.push(m.msg.method_return());
+ Ok(r)
+
+ }
+
+ fn get_managed_objects(&self, m: &MethodInfo<M, D>) -> MethodResult {
+ use arg::{Dict, Variant};
+ let mut paths = m.tree.children(&self, false);
+ paths.push(&self);
+ let mut result = Ok(());
+ let mut r = m.msg.method_return();
+ {
+ let mut 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(&"")));
+ let me = try!(m.member().and_then(|me| i.methods.get(&me)).ok_or_else(|| MethodErr::no_method(&"")));
+ 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.
+ pub fn 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.
+ pub fn add<I: Into<Arc<Interface<M, D>>>>(mut self, 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.
+ pub fn default_interface(mut self, 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.
+ pub fn object_manager(mut self) -> Self {
+ use arg::{Variant, Dict};
+ let ifname = IfaceName::from("org.freedesktop.DBus.ObjectManager");
+ if self.ifaces.contains_key(&ifname) { return self };
+ 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
+ }
+
+ fn add_property_handler(&mut self) {
+ use arg::{Variant, Dict};
+ let ifname = IfaceName::from("org.freedesktop.DBus.Properties");
+ if self.ifaces.contains_key(&ifname) { return };
+ let z = self.ifacecache.get(ifname, |i| {
+ i.add_m(super::leaves::new_method("Get".into(), Default::default(),
+ M::make_method(|m| m.path.prop_get(m)))
+ .inarg::<&str,_>("interface_name")
+ .inarg::<&str,_>("property_name")
+ .outarg::<Variant<()>,_>("value"))
+ .add_m(super::leaves::new_method("GetAll".into(), Default::default(),
+ M::make_method(|m| m.path.prop_get_all(m)))
+ .inarg::<&str,_>("interface_name")
+ .outarg::<Dict<&str, Variant<()>, ()>,_>("props"))
+ .add_m(super::leaves::new_method("Set".into(), Default::default(),
+ M::make_method(|m| m.path.prop_set(m)))
+ .inarg::<&str,_>("interface_name")
+ .inarg::<&str,_>("property_name")
+ .inarg::<Variant<bool>,_>("value"))
+ });
+ self.ifaces.insert(z.name.clone(), z);
+ }
+}
+
+pub fn new_objectpath<M: MethodType<D>, D: DataType>(n: Path<'static>, d: D::ObjectPath, cache: Arc<IfaceCache<M, D>>)
+ -> ObjectPath<M, D> {
+ ObjectPath { name: Arc::new(n), data: d, ifaces: ArcMap::new(), ifacecache: cache, default_iface: None }
+}
+
+
+/// A collection of object paths.
+#[derive(Debug, Default)]
+pub struct Tree<M: MethodType<D>, D: DataType> {
+ paths: ArcMap<Arc<Path<'static>>, ObjectPath<M, D>>,
+ data: D::Tree,
+}
+
+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.
+ pub fn add<I: Into<Arc<ObjectPath<M, D>>>>(mut self, s: I) -> Self {
+ self.insert(s);
+ self
+ }
+
+ /// Get a reference to an object path from the tree.
+ pub fn get(&self, p: &Path<'static>) -> Option<&Arc<ObjectPath<M, D>>> {
+ self.paths.get(p)
+ }
+
+ /// Iterates over object paths in this tree.
+ pub fn 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.
+ pub fn insert<I: Into<Arc<ObjectPath<M, D>>>>(&mut self, 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.
+ pub fn remove(&mut self, 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.
+ pub fn set_registered(&self, c: &Connection, b: bool) -> Result<(), Error> {
+ let mut regd_paths = Vec::new();
+ for p in self.paths.keys() {
+ if b {
+ match c.register_object_path(p) {
+ Ok(()) => regd_paths.push(p.clone()),
+ Err(e) => {
+ while let 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.
+ pub fn 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.
+ pub fn 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
+ pub fn get_data(&self) -> &D::Tree { &self.data }
+
+}
+
+pub fn new_tree<M: MethodType<D>, D: DataType>(d: D::Tree) -> Tree<M, D> {
+ Tree { paths: ArcMap::new(), data: d }
+}
+
+impl<M: MethodType<D>, D: DataType> MsgHandler for Tree<M, D> {
+ fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
+ self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
+ }
+ fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
+}
+
+impl<M: MethodType<D>, D: DataType> MsgHandler for Arc<Tree<M, D>> {
+ fn handle_msg(&mut self, msg: &Message) -> Option<MsgHandlerResult> {
+ self.handle(msg).map(|v| MsgHandlerResult { handled: true, done: false, reply: v })
+ }
+ fn handler_type(&self) -> MsgHandlerType { MsgHandlerType::MsgType(MessageType::MethodCall) }
+}
+
+/// 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.
+pub struct 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(&mut self) -> Option<ConnectionItem> {
+ loop {
+ let n = self.iter.next();
+ if let &Some(ConnectionItem::MethodCall(ref msg)) = &n {
+ if let 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);
+
+ 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">
+<node name="/echo">
+ <interface name="com.example.echo">
+ <method name="Echo">
+ <arg name="request" type="s" direction="in"/>
+ <arg name="reply" type="s" direction="out"/>
+ </method>
+ <property name="EchoCount" type="i" access="read"/>
+ <signal name="Echoed">
+ <arg name="data" type="s"/>
+ <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+ </signal>
+ </interface>
+ <interface name="org.freedesktop.DBus.Introspectable">
+ <method name="Introspect">
+ <arg name="xml_data" type="s" direction="out"/>
+ </method>
+ </interface>
+ <interface name="org.freedesktop.DBus.Properties">
+ <method name="Get">
+ <arg name="interface_name" type="s" direction="in"/>
+ <arg name="property_name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="out"/>
+ </method>
+ <method name="GetAll">
+ <arg name="interface_name" type="s" direction="in"/>
+ <arg name="props" type="a{sv}" direction="out"/>
+ </method>
+ <method name="Set">
+ <arg name="interface_name" type="s" direction="in"/>
+ <arg name="property_name" type="s" direction="in"/>
+ <arg name="value" type="v" direction="in"/>
+ </method>
+ </interface>
+ <node name="subpath"/>
+</node>"##;
+
+ assert_eq!(expected_result, actual_result);
+}
+
diff --git a/third_party/rust/dbus/src/tree/utils.rs b/third_party/rust/dbus/src/tree/utils.rs
new file mode 100644
index 0000000000..5b1418908b
--- /dev/null
+++ b/third_party/rust/dbus/src/tree/utils.rs
@@ -0,0 +1,100 @@
+// Small structs that don't have their own unit.
+
+use {Signature, Member, Path, Interface as IfaceName};
+use std::collections::{BTreeMap, btree_map};
+use std::sync::Arc;
+
+pub type ArcMap<K, V> = BTreeMap<K, Arc<V>>;
+
+#[derive(Clone, Debug)]
+pub enum IterE<'a, V: 'a> {
+ Path(btree_map::Values<'a, Arc<Path<'static>>, Arc<V>>),
+ Iface(btree_map::Values<'a, Arc<IfaceName<'static>>, Arc<V>>),
+ Member(btree_map::Values<'a, Member<'static>, Arc<V>>),
+ String(btree_map::Values<'a, String, Arc<V>>),
+}
+
+#[derive(Clone, Debug)]
+/// Iterator struct, returned from iterator methods on Tree, Objectpath and Interface.
+pub struct Iter<'a, V: 'a>(IterE<'a, V>);
+
+impl<'a, V: 'a> From<IterE<'a, V>> for Iter<'a, V> { fn from(x: IterE<'a, V>) -> Iter<'a, V> { Iter(x) }}
+
+impl<'a, V: 'a> Iterator for Iter<'a, V> {
+ type Item = &'a Arc<V>;
+ fn next(&mut self) -> Option<Self::Item> {
+ match self.0 {
+ IterE::Path(ref mut x) => x.next(),
+ IterE::Iface(ref mut x) => x.next(),
+ IterE::Member(ref mut x) => x.next(),
+ IterE::String(ref mut x) => x.next(),
+ }
+ }
+}
+
+#[derive(Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
+/// A D-Bus Argument.
+pub struct Argument(Option<String>, Signature<'static>);
+
+impl Argument {
+ /// Create a new Argument.
+ pub fn new(name: Option<String>, sig: Signature<'static>) -> Argument { Argument(name, sig) }
+
+ /// Descriptive name (if any).
+ pub fn name(&self) -> Option<&str> { self.0.as_ref().map(|s| &**s) }
+
+ /// Type signature of argument.
+ pub fn signature(&self) -> &Signature<'static> { &self.1 }
+
+ fn introspect(&self, indent: &str, dir: &str) -> String {
+ let n = self.0.as_ref().map(|n| format!("name=\"{}\" ", n)).unwrap_or("".into());
+ format!("{}<arg {}type=\"{}\"{}/>\n", indent, n, self.1, dir)
+ }
+
+}
+
+pub fn introspect_args(args: &[Argument], indent: &str, dir: &str) -> String {
+ args.iter().fold("".to_string(), |aa, az| format!("{}{}", aa, az.introspect(indent, dir)))
+}
+
+// Small helper struct to reduce memory somewhat for objects without annotations
+#[derive(Clone, Debug, Default)]
+pub struct Annotations(Option<BTreeMap<String, String>>);
+
+impl Annotations {
+ pub fn new() -> Annotations { Annotations(None) }
+
+ pub fn insert<N: Into<String>, V: Into<String>>(&mut self, n: N, v: V) {
+ if self.0.is_none() { self.0 = Some(BTreeMap::new()) }
+ self.0.as_mut().unwrap().insert(n.into(), v.into());
+ }
+
+ pub fn introspect(&self, indent: &str) -> String {
+ self.0.as_ref().map(|s| s.iter().fold("".into(), |aa, (ak, av)| {
+ format!("{}{}<annotation name=\"{}\" value=\"{}\"/>\n", aa, indent, ak, av)
+ })).unwrap_or(String::new())
+ }
+}
+
+// Doesn't work, conflicting impls
+// impl<S: Into<Signature>> From<S> for Argument
+
+impl From<Signature<'static>> for Argument {
+ fn from(t: Signature<'static>) -> Argument { Argument(None, t) }
+}
+
+impl<'a> From<&'a str> for Argument {
+ fn from(t: &'a str) -> Argument { Argument(None, String::from(t).into()) }
+}
+
+impl<N: Into<String>, S: Into<Signature<'static>>> From<(N, S)> for Argument {
+ fn from((n, s): (N, S)) -> Argument { Argument(Some(n.into()), s.into()) }
+}
+
+pub trait Introspect {
+ // At some point we might want to switch to fmt::Write / fmt::Formatter for performance...
+ fn xml_name(&self) -> &'static str;
+ fn xml_params(&self) -> String;
+ fn xml_contents(&self) -> String;
+}
+