1use super::utils::{Argument, Annotations, Introspect, introspect_args};
3use super::{MethodType, MethodInfo, MethodResult, MethodErr, DataType, PropInfo, MTFn, MTFnMut, MTSync};
4use dbus::strings::{Interface as IfaceName, Member, Signature, Path};
5use dbus::{arg, Message};
6use std::fmt;
7use std::cell::RefCell;
8use dbus::ffidisp::stdintf::org_freedesktop_dbus::PropertiesPropertiesChanged;
9
10
11struct DebugMethod<M: MethodType<D>, D: DataType>(Box<M::Method>);
13impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugMethod<M, D> {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<Method>") }
15}
16struct DebugGetProp<M: MethodType<D>, D: DataType>(Box<M::GetProp>);
17impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugGetProp<M, D> {
18 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<GetProp>") }
19}
20struct DebugSetProp<M: MethodType<D>, D: DataType>(Box<M::SetProp>);
21impl<M: MethodType<D>, D: DataType> fmt::Debug for DebugSetProp<M, D> {
22 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "<SetProp>") }
23}
24
25
26#[derive(Debug)]
27pub struct Method<M: MethodType<D>, D: DataType> {
29 cb: DebugMethod<M, D>,
30 data: D::Method,
31 name: Member<'static>,
32 i_args: Vec<Argument>,
33 o_args: Vec<Argument>,
34 anns: Annotations,
35}
36
37impl<M: MethodType<D>, D: DataType> Method<M, D> {
38
39 pub fn in_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.i_args.push(a.into()); self }
41 pub fn inarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.i_args.push((s.into(), A::signature()).into()); self }
43 pub fn in_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
45 self.i_args.extend(a.into_iter().map(|b| b.into())); self
46 }
47
48 pub fn out_arg<A: Into<Argument>>(mut self, a: A) -> Self { self.o_args.push(a.into()); self }
50 pub fn outarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.o_args.push((s.into(), A::signature()).into()); self }
52 pub fn out_args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
54 self.o_args.extend(a.into_iter().map(|b| b.into())); self
55 }
56
57 pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
59 self.anns.insert(name, value); self
60 }
61 pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
63
64 pub fn call(&self, minfo: &MethodInfo<M, D>) -> MethodResult { M::call_method(&self.cb.0, minfo) }
66
67 pub fn get_name(&self) -> &Member<'static> { &self.name }
69
70 pub fn get_data(&self) -> &D::Method { &self.data }
72
73}
74
75impl<M: MethodType<D>, D: DataType> Introspect for Method<M, D> {
76 fn xml_name(&self) -> &'static str { "method" }
77 fn xml_params(&self) -> String { String::new() }
78 fn xml_contents(&self) -> String {
79 format!("{}{}{}",
80 introspect_args(&self.i_args, " ", " direction=\"in\""),
81 introspect_args(&self.o_args, " ", " direction=\"out\""),
82 self.anns.introspect(" "))
83 }
84}
85
86pub fn new_method<M: MethodType<D>, D: DataType>(n: Member<'static>, data: D::Method, cb: Box<M::Method>) -> Method<M, D> {
87 Method { name: n, i_args: vec!(), o_args: vec!(), anns: Annotations::new(), cb: DebugMethod(cb), data: data }
88}
89
90
91
92#[derive(Debug)]
93pub struct Signal<D: DataType> {
95 name: Member<'static>,
96 data: D::Signal,
97 arguments: Vec<Argument>,
98 anns: Annotations,
99}
100
101impl<D: DataType> Signal<D> {
102
103 pub fn arg<A: Into<Argument>>(mut self, a: A) -> Self { self.arguments.push(a.into()); self }
105
106 pub fn sarg<A: arg::Arg, S: Into<String>>(mut self, s: S) -> Self { self.arguments.push((s.into(), A::signature()).into()); self }
108
109 pub fn args<Z: Into<Argument>, A: IntoIterator<Item=Z>>(mut self, a: A) -> Self {
111 self.arguments.extend(a.into_iter().map(|b| b.into())); self
112 }
113
114 pub fn annotate<N: Into<String>, V: Into<String>>(mut self, name: N, value: V) -> Self {
116 self.anns.insert(name, value); self
117 }
118 pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
120
121 pub fn get_name(&self) -> &Member<'static> { &self.name }
123
124 pub fn get_data(&self) -> &D::Signal { &self.data }
126
127 pub fn emit<A: arg::Append>(&self, p: &Path<'static>, i: &IfaceName<'static>, items: &[A]) -> Message {
131 let mut m = self.msg(p, i);
132 let mut ia = arg::IterAppend::new(&mut m);
133 for a in items { a.append_by_ref(&mut ia) }
134 m
135 }
136
137 pub fn msg(&self, p: &Path<'static>, i: &IfaceName<'static>) -> Message {
141 Message::signal(p, i, &self.name)
142 }
143
144}
145
146impl<D: DataType> Introspect for Signal<D> {
147 fn xml_name(&self) -> &'static str { "signal" }
148 fn xml_params(&self) -> String { String::new() }
149 fn xml_contents(&self) -> String {
150 format!("{}{}",
151 introspect_args(&self.arguments, " ", ""),
152 self.anns.introspect(" "))
153 }
154}
155
156pub 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)]
161pub enum EmitsChangedSignal {
164 True,
166 Invalidates,
168 Const,
170 False,
172}
173
174#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Debug)]
175pub enum Access {
177 Read,
179 ReadWrite,
181 Write,
183}
184
185impl Access {
186 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
196pub 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)]
215pub 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
228impl<M: MethodType<D>, D: DataType> Property<M, D> {
229
230 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 pub fn auto_emit_on_set(mut self, b: bool) -> Self {
249 self.auto_emit = b;
250 self
251 }
252
253 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 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 pub fn deprecated(self) -> Self { self.annotate("org.freedesktop.DBus.Deprecated", "true") }
272
273 pub fn get_name(&self) -> &str { &self.name }
275
276 pub fn get_data(&self) -> &D::Property { &self.data }
278
279 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 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 pub fn can_set(&self, i: Option<arg::Iter>) -> Result<(), MethodErr> {
301 use dbus::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 = 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 pub fn set_as_variant(&self, i: &mut arg::Iter, pinfo: &PropInfo<M, D>) -> Result<Option<Message>, MethodErr> {
319 use dbus::arg::Arg;
320 let mut subiter = i.recurse(arg::Variant::<bool>::ARG_TYPE).ok_or_else(|| MethodErr::invalid_arg(&2))?;
321 M::call_setprop(&*self.set_cb.as_ref().unwrap().0, &mut subiter, pinfo)?;
322 self.get_emits_changed_signal(pinfo)
323 }
324
325 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 pub fn add_propertieschanged<F: FnOnce() -> Box<dyn arg::RefArg>>(&self, v: &mut Vec<PropertiesPropertiesChanged>, iface: &IfaceName, new_value: F) {
337
338 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
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 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
381impl<'a, D: DataType> Property<MTFn<D>, D> {
382 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 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
402impl<'a, D: DataType> Property<MTFnMut<D>, D> {
403 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 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
422impl<D: DataType> Property<MTSync<D>, D> {
423 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 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
443impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::Append + Clone {
444 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
453impl<M: MethodType<D>, D: DataType> Property<M, D> where D::Property: arg::RefArg {
454 pub fn default_get_refarg(mut self) -> Self {
456 let g = |i: &mut arg::IterAppend, p: &PropInfo<M, D>| { arg::RefArg::append(p.prop.get_data(),i); Ok(()) };
457 self.get_cb = Some(DebugGetProp(M::make_getprop(g)));
458 self
459 }
460}
461
462impl<M: MethodType<D>, D: DataType> Introspect for Property<M, D> {
463 fn xml_name(&self) -> &'static str { "property" }
464 fn xml_params(&self) -> String { format!(" type=\"{}\" access=\"{}\"", self.sig, self.rw.introspect()) }
465 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
478pub 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]
487fn test_prop_handlers() {
488 use crate::Factory;
489 use std::collections::BTreeMap;
490 use dbus::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 msg.set_serial(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 msg.set_serial(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 msg.set_serial(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
534#[test]
535fn test_get_managed_objects() {
536 use std::collections::BTreeMap;
537
538 use crate::Factory;
539 use dbus::arg::{Dict, Variant};
540
541 #[derive(Default, Debug)]
542 struct Custom;
543 impl DataType for Custom {
544 type Tree = ();
545 type ObjectPath = ();
546 type Interface = ();
547 type Property = i32;
548 type Method = ();
549 type Signal = ();
550 }
551
552 let f = Factory::new_fn::<Custom>();
553 let tree = f.tree(()).add(f.object_path("/test", ()).introspectable().object_manager()
554 .add(f.interface("com.example.test", ())
555 .add_p(f.property::<i32,_>("Value1", 5i32).default_get())
556 .add_p(f.property::<i32,_>("Value2", 9i32).default_get())
557 )
558 ).add(f.object_path("/test/subtest", ()).introspectable()
559 .add(f.interface("com.example.subtest", ())
560 .add_p(f.property::<i32, _>("Value3", 7i32).default_get())
561 )
562 );
563
564 let mut msg = Message::new_method_call("com.example.test", "/test", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects").unwrap();
565 msg.set_serial(4);
566 let res = tree.handle(&msg).unwrap();
567 let pdict: arg::Dict<Path, Dict<&str, Dict<&str, Variant<i32>, _>, _>, _> = res[0].get1().unwrap();
568 let pmap: BTreeMap<_, _> = pdict.collect();
569
570 assert!(pmap.get(&Path::from("/test")).is_none());
571
572 let idict = pmap.get(&Path::from("/test/subtest")).unwrap();
573 let imap: BTreeMap<_, _> = idict.collect();
574 let propdict = imap.get("com.example.subtest").unwrap();
575 let propmap: BTreeMap<_, _> = propdict.collect();
576 assert_eq!(propmap.get("Value3"), Some(&arg::Variant(7i32)));
577}
578
579#[test]
580fn test_set_prop() {
581 use crate::{Factory, Access};
582 use std::cell::{Cell, RefCell};
583 use std::collections::BTreeMap;
584 use std::rc::Rc;
585
586 let changes = Rc::new(Cell::new(0i32));
587 let (changes1, changes2) = (changes.clone(), changes.clone());
588 let setme = Rc::new(RefCell::new("I have not been set yet!".to_owned()));
589 let (setme1, setme2) = (setme.clone(), setme.clone());
590
591 let f = Factory::new_fn::<()>();
592 let tree = f.tree(()).add(f.object_path("/example", ()).introspectable()
593 .add(f.interface("com.example.dbus.rs", ())
594 .add_p(f.property::<i32,_>("changes", ())
595 .on_get(move |i, _| { i.append(changes1.get()); Ok(()) }))
596 .add_p(f.property::<String,_>("setme", ())
597 .access(Access::ReadWrite)
598 .on_get(move |i, _| { i.append(&*setme1.borrow()); Ok(()) })
599 .on_set(move |i, _| {
600 *setme2.borrow_mut() = i.get().unwrap();
601 changes2.set(changes2.get() + 1);
602 Ok(())
603 }))
604 )
605 );
606
607 let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
609 .append3("com.example.dbus.rs", "changes", arg::Variant(5i32));
610 msg.set_serial(20);
611 let mut r = tree.handle(&msg).unwrap();
612 assert!(r.get_mut(0).unwrap().as_result().is_err());
613
614 let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
616 .append3("com.example.dbus.rs", "setme", arg::Variant(8i32));
617 msg.set_serial(30);
618 let mut r = tree.handle(&msg).unwrap();
619 assert!(r.get_mut(0).unwrap().as_result().is_err());
620
621 let mut msg = Message::new_method_call("com.example.dbus.rs", "/example", "org.freedesktop.DBus.Properties", "Set").unwrap()
623 .append3("com.example.dbus.rs", "setme", arg::Variant("Correct"));
624 msg.set_serial(30);
625 let r = tree.handle(&msg).unwrap();
626
627 assert_eq!(changes.get(), 1);
628 assert_eq!(&**setme.borrow(), "Correct");
629
630 println!("{:?}", r);
631 assert_eq!(r.len(), 2);
632 assert_eq!(&*r[0].member().unwrap(), "PropertiesChanged");
633 let (s, d): (Option<&str>, Option<arg::Dict<&str, arg::Variant<_>, _>>) = r[0].get2();
634 assert_eq!(s, Some("com.example.dbus.rs"));
635 let z2: BTreeMap<_, _> = d.unwrap().collect();
636 assert_eq!(z2.get("setme"), Some(&arg::Variant("Correct")));
637
638}
639
640
641#[test]
642fn test_sync_prop() {
643 use std::sync::atomic::{AtomicUsize, Ordering};
644 use std::sync::Arc;
645 use crate::{Factory, Access, EmitsChangedSignal};
646
647 let f = Factory::new_sync::<()>();
648
649 let count = Arc::new(AtomicUsize::new(3));
650 let (cget, cset) = (count.clone(), count.clone());
651
652 let tree1 = Arc::new(f.tree(()).add(f.object_path("/syncprop", ()).introspectable()
653 .add(f.interface("com.example.syncprop", ())
654 .add_p(f.property::<u32,_>("syncprop", ())
655 .access(Access::ReadWrite)
656 .emits_changed(EmitsChangedSignal::False)
657 .on_get(move |i,_| { i.append(cget.load(Ordering::SeqCst) as u32); Ok(()) })
658 .on_set(move |i,_| { cset.store(i.get::<u32>().unwrap() as usize, Ordering::SeqCst); Ok(()) })
659 )
660 )
661 ));
662
663 let tree2 = tree1.clone();
664 println!("{:#?}", tree2);
665
666 ::std::thread::spawn(move || {
667 let mut msg = Message::new_method_call("com.example.syncprop", "/syncprop", "org.freedesktop.DBus.Properties", "Set").unwrap()
668 .append3("com.example.syncprop", "syncprop", arg::Variant(5u32));
669 msg.set_serial(30);
670 let mut r = tree2.handle(&msg).unwrap();
671 assert!(r[0].as_result().is_ok());
672 });
673
674 loop {
675 let mut msg = Message::new_method_call("com.example.echoserver", "/syncprop", "org.freedesktop.DBus.Properties", "Get").unwrap()
676 .append1("com.example.syncprop").append1("syncprop");
677 msg.set_serial(4);
678 let mut r = tree1.handle(&msg).unwrap();
679 let r = r[0].as_result().unwrap();
680 let z: arg::Variant<u32> = r.get1().unwrap();
681 if z.0 == 5 { break; }
682 assert_eq!(z.0, 3);
683 }
684 assert_eq!(count.load(Ordering::SeqCst), 5);
685}