1 // Methods, signals, properties, and interfaces.
2 use super::utils::{Argument, Annotations, Introspect, introspect_args};
3 use super::{MethodType, MethodInfo, MethodResult, MethodErr, DataType, PropInfo, MTFn, MTFnMut, MTSync};
4 use {Member, Signature, Message, Path, MessageItem};
5 use Interface as IfaceName;
6 use arg;
7 use std::fmt;
8 use std::cell::RefCell;
9 use stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
10 
11 
12 // Workaround for https://github.com/rust-lang/rust/issues/31518
13 struct DebugMethod<M: MethodType<D>, D: DataType>(Box<M::Method>);
14 impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugMethod<M, D> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result15     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Method>") }
16 }
17 struct DebugGetProp<M: MethodType<D>, D: DataType>(Box<M::GetProp>);
18 impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugGetProp<M, D> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result19     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<GetProp>") }
20 }
21 struct DebugSetProp<M: MethodType<D>, D: DataType>(Box<M::SetProp>);
22 impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugSetProp<M, D> {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result23     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<SetProp>") }
24 }
25 
26 
27 #[derive(Debug)]
28 /// A D-Bus Method.
29 pub struct Method<M: MethodType<D>, D: DataType> {
30     cb: DebugMethod<M, D>,
31     data: D::Method,
32     name: Member<'static>,
33     i_args: Vec<Argument>,
34     o_args: Vec<Argument>,
35     anns: Annotations,
36 }
37 
38 impl<M: MethodType<D>, D: DataType> Method<M, D> {
39 
40     /// Builder method that adds an "in" Argument to this Method.
in_arg<A: Into<Argument>>(mut self, a: A) -> Self41     pub fn in_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.i_args.push(a.into()); self }
42     /// Builder method that adds an "in" Argument to this Method.
inarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self43     pub fn inarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.i_args.push((s.into(), A::signature()).into()); self }
44     /// Builder method that adds multiple "in" Arguments to this Method.
in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self45     pub fn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
46         self.i_args.extend(a.into_iter().map(|b| b.into())); self
47     }
48 
49     /// Builder method that adds an "out" Argument to this Method.
out_arg<A: Into<Argument>>(mut self, a: A) -> Self50     pub fn out_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.o_args.push(a.into()); self }
51     /// Builder method that adds an "out" Argument to this Method.
outarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self52     pub fn outarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.o_args.push((s.into(), A::signature()).into()); self }
53     /// Builder method that adds multiple "out" Arguments to this Method.
out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self54     pub fn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
55         self.o_args.extend(a.into_iter().map(|b| b.into())); self
56     }
57 
58     /// Builder method that adds an annotation to the method.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self59     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
60         self.anns.insert(name, value); self
61     }
62     /// Builder method that adds an annotation that this entity is deprecated.
deprecated(self) -> Self63     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
64 
65     /// Call the Method
call(&self, minfo: &MethodInfo<M, D>) -> MethodResult66     pub fn call(&self, minfo: &MethodInfo<M, D>) -> MethodResult { M::call_method(&self.cb.0, minfo) }
67 
68     /// Get method name
get_name(&self) -> &Member<'static>69     pub fn get_name(&self) -> &Member<'static> { &self.name }
70 
71     /// Get associated data
get_data(&self) -> &D::Method72     pub fn get_data(&self) -> &D::Method { &self.data }
73 
74 }
75 
76 impl<M: MethodType<D>, D: DataType> Introspect for Method<M, D> {
xml_name(&self) -> &'static str77     fn xml_name(&self) -> &'static str { "method" }
xml_params(&self) -> String78     fn xml_params(&self) -> String { String::new() }
xml_contents(&self) -> String79     fn xml_contents(&self) -> String {
80         format!("{}{}{}",
81             introspect_args(&self.i_args, "      ", " direction=\"in\""),
82             introspect_args(&self.o_args, "      ", " direction=\"out\""),
83             self.anns.introspect("      "))
84     }
85 }
86 
new_method<M: MethodType<D>, D: DataType>(n: Member<'static>, data: D::Method, cb: Box<M::Method>) -> Method<M, D>87 pub fn new_method<M: MethodType<D>, D: DataType>(n: Member<'static>, data: D::Method, cb: Box<M::Method>) -> Method<M, D> {
88     Method { name: n, i_args: vec!(), o_args: vec!(), anns: Annotations::new(), cb: DebugMethod(cb), data: data }
89 }
90 
91 
92 
93 #[derive(Debug)]
94 /// A D-Bus Signal.
95 pub struct Signal<D: DataType> {
96     name: Member<'static>,
97     data: D::Signal,
98     arguments: Vec<Argument>,
99     anns: Annotations,
100 }
101 
102 impl<D: DataType> Signal<D> {
103 
104     /// Builder method that adds an Argument to the Signal.
arg<A: Into<Argument>>(mut self, a: A) -> Self105     pub fn arg<A: Into<Argument>>(mut self, a: A) -> Self { self.arguments.push(a.into()); self }
106 
107     /// Builder method that adds an Argument to the Signal.
sarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self108     pub fn sarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.arguments.push((s.into(), A::signature()).into()); self }
109 
110     /// Builder method that adds multiple Arguments to the Signal.
args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self111     pub fn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
112         self.arguments.extend(a.into_iter().map(|b| b.into())); self
113     }
114 
115     /// Add an annotation to this Signal.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self116     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
117         self.anns.insert(name, value); self
118     }
119     /// Add an annotation that this entity is deprecated.
deprecated(self) -> Self120     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
121 
122     /// Get signal name
get_name(&self) -> &Member<'static>123     pub fn get_name(&self) -> &Member<'static> { &self.name }
124 
125     /// Get associated data
get_data(&self) -> &D::Signal126     pub fn get_data(&self) -> &D::Signal { &self.data }
127 
128     /// Returns a message which emits the signal when sent.
129     ///
130     /// Same as "msg" but also takes a "MessageItem" argument.
emit(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[MessageItem]) -> Message131     pub fn emit(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[MessageItem]) -> Message {
132         let mut m = self.msg(p, i);
133         m.append_items(items);
134         m
135     }
136 
137     /// Returns a message which emits the signal when sent.
138     ///
139     /// Same as "emit" but does not take a "MessageItem" argument.
msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message140     pub fn msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message {
141         Message::signal(p, i, &self.name)
142     }
143 
144 }
145 
146 impl<D: DataType> Introspect for Signal<D> {
xml_name(&self) -> &'static str147     fn xml_name(&self) -> &'static str { "signal" }
xml_params(&self) -> String148     fn xml_params(&self) -> String { String::new() }
xml_contents(&self) -> String149     fn xml_contents(&self) -> String {
150         format!("{}{}",
151             introspect_args(&self.arguments, "      ", ""),
152             self.anns.introspect("      "))
153     }
154 }
155 
new_signal<D: DataType>(n: Member<'static>, data: D::Signal) -> Signal<D>156 pub fn new_signal<D: DataType>(n: Member<'static>, data: D::Signal) -> Signal<D> {
157     Signal { name: n, arguments: vec!(), anns: Annotations::new(), data: data }
158 }
159 
160 #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
161 /// Enumerates the different signaling behaviors a Property can have
162 /// to being changed.
163 pub enum EmitsChangedSignal {
164     /// The Property emits a signal that includes the new value.
165     True,
166     /// The Property emits a signal that does not include the new value.
167     Invalidates,
168     /// The Property cannot be changed.
169     Const,
170     /// The Property does not emit a signal when changed.
171     False,
172 }
173 
174 #[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
175 /// The possible access characteristics a Property can have.
176 pub enum Access {
177     /// The Property can only be read (Get).
178     Read,
179     /// The Property can be read or written.
180     ReadWrite,
181     /// The Property can only be written (Set).
182     Write,
183 }
184 
185 impl Access {
introspect(&self) -> &'static str186     fn introspect(&self) -> &'static str {
187         match self {
188             &Access::Read => "read",
189             &Access::ReadWrite => "readwrite",
190             &Access::Write => "write",
191         }
192     }
193 }
194 
195 
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>196 pub fn prop_append_dict<'v, M: MethodType<D> + 'v, D: DataType + 'v, I: Iterator<Item=&'v Property<M, D>>>
197     (iter: &mut arg::IterAppend, mut props: I, minfo: &MethodInfo<M, D>) -> Result<(), MethodErr> {
198 
199     let mut result = Ok(());
200     iter.append_dict(&Signature::make::<&str>(), &Signature::make::<arg::Variant<bool>>(), |subiter| loop {
201         let p = if let Some(p) = props.next() { p } else { return };
202         if p.can_get().is_err() { continue; }
203         let pinfo = minfo.to_prop_info(minfo.iface, p);
204         subiter.append_dict_entry(|mut entryiter| {
205             entryiter.append(&*p.get_name());
206             result = p.get_as_variant(&mut entryiter, &pinfo);
207         });
208         if result.is_err() { return };
209     });
210     result
211 }
212 
213 
214 #[derive(Debug)]
215 /// A D-Bus Property.
216 pub struct Property<M: MethodType<D>, D: DataType> {
217     name: String,
218     data: D::Property,
219     sig: Signature<'static>,
220     emits: EmitsChangedSignal,
221     auto_emit: bool,
222     rw: Access,
223     get_cb: Option<DebugGetProp<M, D>>,
224     set_cb: Option<DebugSetProp<M, D>>,
225     anns: Annotations,
226 }
227 
228 impl<M: MethodType<D>, D: DataType> Property<M, D> {
229 
230     /// Builder method that allows setting the Property's signal
231     /// behavior when changed.
232     ///
233     /// Note: if e is set to const, the property will be read only.
emits_changed(mut self, e: EmitsChangedSignal) -> Self234     pub fn emits_changed(mut self, e: EmitsChangedSignal) -> Self {
235         self.emits = e;
236         if self.emits == EmitsChangedSignal::Const { self.rw = Access::Read };
237         self
238     }
239 
240     /// Builder method that determines whether or not setting this property
241     /// will result in an PropertiesChanged signal. Defaults to true.
242     ///
243     /// When set to true (the default), the behaviour is determined by "emits_changed".
244     /// When set to false, no PropertiesChanged signal will be emitted (but the signal
245     /// still shows up in introspection data).
246     /// You can still emit the signal manually by, e g, calling `add_propertieschanged`
247     /// and send the resulting message(s).
auto_emit_on_set(mut self, b: bool) -> Self248     pub fn auto_emit_on_set(mut self, b: bool) -> Self {
249         self.auto_emit = b;
250         self
251     }
252 
253     /// Builder method that allows setting the Property as readable,
254     /// writable, or both.
255     ///
256     /// Note: might modify emits_changed as well, if property is changed to non-readonly and emit is set to "Const".
access(mut self, e: Access) -> Self257     pub fn access(mut self, e: Access) -> Self {
258         self.rw = e;
259         if self.rw != Access::Read && self.emits == EmitsChangedSignal::Const {
260             self.emits = EmitsChangedSignal::False
261         };
262         self
263     }
264 
265     /// Builder method that adds an annotation to the method.
annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self266     pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
267         self.anns.insert(name, value); self
268     }
269 
270     /// Builder method that adds an annotation that this entity is deprecated.
deprecated(self) -> Self271     pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
272 
273     /// Get property name
get_name(&self) -> &str274     pub fn get_name(&self) -> &str { &self.name }
275 
276     /// Get associated data
get_data(&self) -> &D::Property277     pub fn get_data(&self) -> &D::Property { &self.data }
278 
279     /// Returns Ok if the property is gettable
can_get(&self) -> Result<(), MethodErr>280     pub fn can_get(&self) -> Result<(), MethodErr> {
281         if self.rw == Access::Write || self.get_cb.is_none() {
282             Err(MethodErr::failed(&format!("Property {} is write only", &self.name)))
283         } else { Ok(()) }
284     }
285 
286     /// Calls the on_get function and appends the result as a variant.
287     ///
288     /// Note: Will panic if get_cb is not set.
get_as_variant(&self, i: &mut arg::IterAppend, pinfo: &PropInfo<M, D>) -> Result<(), MethodErr>289     pub fn get_as_variant(&self, i: &mut arg::IterAppend, pinfo: &PropInfo<M, D>) -> Result<(), MethodErr> {
290         let mut r = Ok(());
291         i.append_variant(&self.sig, |subi| {
292             r = M::call_getprop(&*self.get_cb.as_ref().unwrap().0, subi, pinfo);
293         });
294         r
295     }
296 
297     /// Returns Ok if the property is settable.
298     ///
299     /// Will verify signature in case iter is not None; iter is supposed to point at the Variant with the item inside.
can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr>300     pub fn can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr> {
301         use arg::Arg;
302         if self.rw == Access::Read || self.set_cb.is_none() || self.emits == EmitsChangedSignal::Const {
303             return Err(MethodErr::ro_property(&self.name))
304         }
305         if let Some(mut i) = i {
306             let mut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2)));
307             if &*subiter.signature() != &*self.sig {
308                return Err(MethodErr::failed(&format!("Property {} cannot change type", &self.name)))
309             }
310         }
311         Ok(())
312     }
313 
314     /// Calls the on_set function, which reads from i.
315     ///
316     /// The return value might contain an extra message containing the EmitsChanged signal.
317     /// Note: Will panic if set_cb is not set.
set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr>318     pub fn set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
319         use arg::Arg;
320         let mut subiter = try!(i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2)));
321         try!(M::call_setprop(&*self.set_cb.as_ref().unwrap().0, &mut subiter, pinfo));
322         self.get_emits_changed_signal(pinfo)
323     }
324 
325     /// Gets the signal (if any) associated with the Property.
get_signal(&self, p: &PropInfo<M, D>) -> Message326     fn get_signal(&self, p: &PropInfo<M, D>) -> Message {
327         Message::signal(p.path.get_name(), &"org.freedesktop.DBus.Properties".into(), &"PropertiesChanged".into())
328             .append1(&**p.iface.get_name())
329     }
330 
331     /// Adds this property to a list of PropertiesChanged signals.
332     ///
333     /// "v" is updated with the signal for this property. "new_value" is only called if self.emits is "true",
334     /// it should return the value of the property.
335     /// If no PropertiesChanged signal should be emitted for this property, "v" is left unchanged.
add_propertieschanged<F: FnOnce() -> Box<arg::RefArg>>(&self, v: &mut Vec<PropertiesPropertiesChanged>, iface: &IfaceName, new_value: F)336     pub fn add_propertieschanged<F: FnOnce() -> Box<arg::RefArg>>(&self, v: &mut Vec<PropertiesPropertiesChanged>, iface: &IfaceName, new_value: F) {
337 
338         // Impl note: It is a bit silly that this function cannot be used from e g get_emits_changed_signal below,
339         // but it is due to the fact that we cannot create a RefArg out of an IterAppend; which is what the 'on_get'
340         // handler currently receives.
341 
342         if self.emits == EmitsChangedSignal::Const || self.emits == EmitsChangedSignal::False { return; }
343         let vpos = v.iter().position(|vv| &*vv.interface_name == &**iface);
344         let vpos = vpos.unwrap_or_else(|| {
345             let mut z: PropertiesPropertiesChanged = Default::default();
346             z.interface_name = (&**iface).into();
347             v.push(z);
348             v.len()-1
349         });
350 
351         let vv = &mut v[vpos];
352         if self.emits == EmitsChangedSignal::Invalidates {
353             vv.invalidated_properties.push(self.name.clone());
354         } else {
355             vv.changed_properties.insert(self.name.clone(), arg::Variant(new_value()));
356         }
357     }
358 
get_emits_changed_signal(&self, m: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr>359     fn get_emits_changed_signal(&self, m: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
360         if !self.auto_emit { return Ok(None) }
361         match self.emits {
362             EmitsChangedSignal::False => Ok(None),
363             EmitsChangedSignal::Const => Err(MethodErr::ro_property(&self.name)),
364             EmitsChangedSignal::True => Ok(Some({
365                 let mut s = self.get_signal(m);
366                 {
367                     let mut iter = arg::IterAppend::new(&mut s);
368                     try!(prop_append_dict(&mut iter, Some(self).into_iter(), &m.to_method_info()));
369                     iter.append(arg::Array::<&str, _>::new(vec!()));
370                 }
371                 s
372             })),
373             EmitsChangedSignal::Invalidates => Ok(Some(self.get_signal(m).append2(
374                 arg::Dict::<&str, arg::Variant<bool>, _>::new(vec!()),
375                 arg::Array::new(Some(&*self.name).into_iter())
376             ))),
377         }
378     }
379 }
380 
381 impl<'a, D: DataType> Property<MTFn<D>, D> {
382     /// Sets the callback for getting a property.
383     ///
384     /// For single-thread use.
on_get<H>(mut self, handler: H) -> Property<MTFn<D>, D> where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr>385     pub fn on_get<H>(mut self, handler: H) -> Property<MTFn<D>, D>
386         where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
387         self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
388         self
389     }
390 
391     /// Sets the callback for setting a property.
392     ///
393     /// For single-thread use.
on_set<H>(mut self, handler: H) -> Property<MTFn<D>, D> where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr>394     pub fn on_set<H>(mut self, handler: H) -> Property<MTFn<D>, D>
395         where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFn<D>, D>) -> Result<(), MethodErr> {
396         self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
397         self
398     }
399 }
400 
401 
402 impl<'a, D: DataType> Property<MTFnMut<D>, D> {
403     /// Sets the callback for getting a property.
404     ///
405     /// For single-thread use.
on_get<H>(mut self, handler: H) -> Property<MTFnMut<D>, D> where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr>406     pub fn on_get<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
407         where H: 'static + Fn(&mut arg::IterAppend, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
408         self.get_cb = Some(DebugGetProp(Box::new(RefCell::new(handler)) as Box<_>));
409         self
410     }
411 
412     /// Sets the callback for setting a property.
413     ///
414     /// For single-thread use.
on_set<H>(mut self, handler: H) -> Property<MTFnMut<D>, D> where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr>415     pub fn on_set<H>(mut self, handler: H) -> Property<MTFnMut<D>, D>
416         where H: 'static + Fn(&mut arg::Iter, &PropInfo<MTFnMut<D>, D>) -> Result<(), MethodErr> {
417         self.set_cb = Some(DebugSetProp(Box::new(RefCell::new(handler)) as Box<_>));
418         self
419     }
420 }
421 
422 impl<D: DataType> Property<MTSync<D>, D> {
423     /// Sets the callback for getting a property.
424     ///
425     /// For multi-thread use.
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 + 'static426     pub fn on_get<H>(mut self, handler: H) -> Property<MTSync<D>, D>
427         where H: Fn(&mut arg::IterAppend, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
428         self.get_cb = Some(DebugGetProp(Box::new(handler) as Box<_>));
429         self
430     }
431 
432     /// Sets the callback for setting a property.
433     ///
434     /// For single-thread use.
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 + 'static435     pub fn on_set<H>(mut self, handler: H) -> Property<MTSync<D>, D>
436         where H: Fn(&mut arg::Iter, &PropInfo<MTSync<D>, D>) -> Result<(), MethodErr> + Send + Sync + 'static {
437         self.set_cb = Some(DebugSetProp(Box::new(handler) as Box<_>));
438         self
439     }
440 }
441 
442 
443 impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::Append + Clone {
444     /// Adds a "standard" get handler.
default_get(mut self) -> Self445     pub fn default_get(mut self) -> Self {
446         let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { i.append(p.prop.get_data()); Ok(()) };
447         self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
448         self
449     }
450 }
451 
452 
453 impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::RefArg {
454     /// Adds a "standard" get handler (for RefArgs).
default_get_refarg(mut self) -> Self455     pub fn default_get_refarg(mut self) -> Self {
456         let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { (p.prop.get_data() as &arg::RefArg).append(i); Ok(()) };
457         self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
458         self
459     }
460 }
461 
462 impl<M: MethodType<D>, D: DataType> Introspect for Property<M, D> {
xml_name(&self) -> &'static str463     fn xml_name(&self) -> &'static str { "property" }
xml_params(&self) -> String464     fn xml_params(&self) -> String { format!(" type=\"{}\" access=\"{}\"", self.sig, self.rw.introspect()) }
xml_contents(&self) -> String465     fn xml_contents(&self) -> String {
466         let s = match self.emits {
467              EmitsChangedSignal::True => return self.anns.introspect("      "),
468              EmitsChangedSignal::False => "false",
469              EmitsChangedSignal::Const => "const",
470              EmitsChangedSignal::Invalidates => "invalidates",
471         };
472         let mut tempanns = self.anns.clone();
473         tempanns.insert("org.freedesktop.DBus.Property.EmitsChangedSignal", s);
474         tempanns.introspect("      ")
475     }
476 }
477 
new_property<M: MethodType<D>, D: DataType> (n: String, sig: Signature<'static>, data: D::Property) -> Property<M, D>478 pub fn new_property<M: MethodType<D>, D: DataType>
479     (n: String, sig: Signature<'static>, data: D::Property) -> Property<M, D> {
480     Property {
481         name: n, emits: EmitsChangedSignal::True, auto_emit: true, rw: Access::Read,
482         sig: sig, anns: Annotations::new(), set_cb: None, get_cb: None, data: data
483     }
484 }
485 
486 #[test]
test_prop_handlers()487 fn test_prop_handlers() {
488     use tree::Factory;
489     use std::collections::BTreeMap;
490     use arg::{Dict, Variant};
491 
492     #[derive(Default, Debug)]
493     struct Custom;
494     impl DataType for Custom {
495         type Tree = ();
496         type ObjectPath = ();
497         type Interface = ();
498         type Property = i32;
499         type Method = ();
500         type Signal = ();
501     }
502 
503     let f = Factory::new_fn::<Custom>();
504     let tree = f.tree(()).add(f.object_path("/test", ()).introspectable().object_manager()
505         .add(f.interface("com.example.test", ())
506             .add_p(f.property::<i32,_>("Value1", 5i32).default_get())
507             .add_p(f.property::<i32,_>("Value2", 9i32).default_get())
508         )
509     );
510 
511     let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Get").unwrap()
512         .append2("com.example.test", "Value1");
513     ::message::message_set_serial(&mut msg, 4);
514     let res = tree.handle(&msg).unwrap();
515     assert_eq!(res[0].get1(), Some(arg::Variant(5i32)));
516 
517     let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "Set").unwrap()
518         .append3("com.example.test", "Value1", arg::Variant(3i32));
519     ::message::message_set_serial(&mut msg, 4);
520     let mut res = tree.handle(&msg).unwrap();
521     assert!(res[0].as_result().is_err());
522 
523     let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.Properties", "GetAll").unwrap()
524         .append1("com.example.test");
525     ::message::message_set_serial(&mut msg, 4);
526     let res = tree.handle(&msg).unwrap();
527     let d: Dict<&str, Variant<i32>, _> = res[0].get1().unwrap();
528     let z2: BTreeMap<_, _> = d.collect();
529     assert_eq!(z2.get("Value1"), Some(&arg::Variant(5i32)));
530     assert_eq!(z2.get("Value2"), Some(&arg::Variant(9i32)));
531     assert_eq!(z2.get("Mooh"), None);
532 
533     let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects").unwrap();
534     ::message::message_set_serial(&mut msg, 4);
535     let res = tree.handle(&msg).unwrap();
536     let pdict: arg::Dict<Path, Dict<&str, Dict<&str, Variant<i32>, _>, _>, _> = res[0].get1().unwrap();
537     let pmap: BTreeMap<_, _> = pdict.collect();
538     let idict = pmap.get(&Path::from("/test")).unwrap();
539     let imap: BTreeMap<_, _> = idict.collect();
540     let propdict = imap.get("com.example.test").unwrap();
541     let propmap: BTreeMap<_, _> = propdict.collect();
542     assert_eq!(propmap.get("Value1"), Some(&arg::Variant(5i32)));
543     assert_eq!(propmap.get("Value2"), Some(&arg::Variant(9i32)));
544     assert_eq!(propmap.get("Mooh"), None);
545 }
546 
547 #[test]
test_set_prop()548 fn test_set_prop() {
549     use tree::{Factory, Access};
550     use std::cell::{Cell, RefCell};
551     use std::collections::BTreeMap;
552     use std::rc::Rc;
553 
554     let changes = Rc::new(Cell::new(0i32));
555     let (changes1, changes2) = (changes.clone(), changes.clone());
556     let setme = Rc::new(RefCell::new("I have not been set yet!".to_owned()));
557     let (setme1, setme2) = (setme.clone(), setme.clone());
558 
559     let f = Factory::new_fn::<()>();
560     let tree = f.tree(()).add(f.object_path("/example", ()).introspectable()
561         .add(f.interface("com.example.dbus.rs", ())
562             .add_p(f.property::<i32,_>("changes", ())
563                 .on_get(move |i, _| { i.append(changes1.get()); Ok(()) }))
564             .add_p(f.property::<String,_>("setme", ())
565                 .access(Access::ReadWrite)
566                 .on_get(move |i, _| { i.append(&*setme1.borrow()); Ok(()) })
567                 .on_set(move |i, _| {
568                     *setme2.borrow_mut() = i.get().unwrap();
569                     changes2.set(changes2.get() + 1);
570                     Ok(())
571                 }))
572         )
573     );
574 
575     // Read-only
576     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
577         .append3("com.example.dbus.rs", "changes", arg::Variant(5i32));
578     ::message::message_set_serial(&mut msg, 20);
579     let mut r = tree.handle(&msg).unwrap();
580     assert!(r.get_mut(0).unwrap().as_result().is_err());
581 
582     // Wrong type
583     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
584         .append3("com.example.dbus.rs", "setme", arg::Variant(8i32));
585     ::message::message_set_serial(&mut msg, 30);
586     let mut r = tree.handle(&msg).unwrap();
587     assert!(r.get_mut(0).unwrap().as_result().is_err());
588 
589     // Correct!
590     let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
591         .append3("com.example.dbus.rs", "setme", arg::Variant("Correct"));
592     ::message::message_set_serial(&mut msg, 30);
593     let r = tree.handle(&msg).unwrap();
594 
595     assert_eq!(changes.get(), 1);
596     assert_eq!(&**setme.borrow(), "Correct");
597 
598     println!("{:?}", r);
599     assert_eq!(r.len(), 2);
600     assert_eq!(&*r[0].member().unwrap(), "PropertiesChanged");
601     let (s, d): (Option<&str>, Option<arg::Dict<&str, arg::Variant<_>, _>>) = r[0].get2();
602     assert_eq!(s, Some("com.example.dbus.rs"));
603     let z2: BTreeMap<_, _> = d.unwrap().collect();
604     assert_eq!(z2.get("setme"), Some(&arg::Variant("Correct")));
605 
606 }
607 
608 
609 #[test]
test_sync_prop()610 fn test_sync_prop() {
611     use std::sync::atomic::{AtomicUsize, Ordering};
612     use std::sync::Arc;
613     use tree::{Factory, Access, EmitsChangedSignal};
614 
615     let f = Factory::new_sync::<()>();
616 
617     let count = Arc::new(AtomicUsize::new(3));
618     let (cget, cset) = (count.clone(), count.clone());
619 
620     let tree1 = Arc::new(f.tree(()).add(f.object_path("/syncprop", ()).introspectable()
621         .add(f.interface("com.example.syncprop", ())
622             .add_p(f.property::<u32,_>("syncprop", ())
623                 .access(Access::ReadWrite)
624                 .emits_changed(EmitsChangedSignal::False)
625                 .on_get(move |i,_| { i.append(cget.load(Ordering::SeqCst) as u32); Ok(()) })
626                 .on_set(move |i,_| { cset.store(i.get::<u32>().unwrap() as usize, Ordering::SeqCst); Ok(()) })
627             )
628         )
629     ));
630 
631     let tree2 = tree1.clone();
632     println!("{:#?}", tree2);
633 
634     ::std::thread::spawn(move || {
635         let mut msg = Message::new_method_call("com.example.syncprop", "/syncprop", "org.freedesktop.DBus.Properties", "Set").unwrap()
636             .append3("com.example.syncprop", "syncprop", arg::Variant(5u32));
637          ::message::message_set_serial(&mut msg, 30);
638          let mut r = tree2.handle(&msg).unwrap();
639          assert!(r[0].as_result().is_ok());
640     });
641 
642     loop {
643         let mut msg = Message::new_method_call("com.example.echoserver", "/syncprop", "org.freedesktop.DBus.Properties", "Get").unwrap()
644             .append("com.example.syncprop").append1("syncprop");
645         ::message::message_set_serial(&mut msg, 4);
646         let mut r = tree1.handle(&msg).unwrap();
647         let r = r[0].as_result().unwrap();
648         let z: arg::Variant<u32> = r.get1().unwrap();
649         if z.0 == 5 { break; }
650         assert_eq!(z.0, 3);
651    }
652    assert_eq!(count.load(Ordering::SeqCst), 5);
653 }
654