1 use super::{MethodType, DataType, MTFn, MTFnMut, MTSync, MethodResult, MethodInfo};
2 use super::{Tree, ObjectPath, Interface, Property, Signal, Method};
3 use super::objectpath::IfaceCache;
4 use std::sync::Arc;
5 use Interface as IfaceName;
6 use {Member, Path, arg};
7 use std::cell::RefCell;
8 
9 /// The factory is used to create object paths, interfaces, methods etc.
10 ///
11 /// There are three factories:
12 ///
13 ///  **MTFn** - all methods are `Fn()`.
14 ///
15 ///  **MTFnMut** - all methods are `FnMut()`. This means they can mutate their environment,
16 ///  which has the side effect that if you call it recursively, it will RefCell panic.
17 ///
18 ///  **MTSync** - all methods are `Fn() + Send + Sync + 'static`. This means that the methods
19 ///  can be called from different threads in parallel.
20 ///
21 #[derive(Debug, Clone)]
22 pub struct Factory<M: MethodType<D>, D: DataType=()>(Arc<IfaceCache<M, D>>);
23 
24 impl<M: MethodType<D>, D: DataType> From<Arc<IfaceCache<M, D>>> for Factory<M, D> {
from(f: Arc<IfaceCache<M, D>>) -> Self25     fn from(f: Arc<IfaceCache<M, D>>) -> Self { Factory(f) }
26 }
27 
28 impl Factory<MTFn<()>, ()> {
29     /// Creates a new factory for single-thread use.
new_fn<D: DataType>() -> Factory<MTFn<D>, D>30     pub fn new_fn<D: DataType>() -> Factory<MTFn<D>, D> { Factory(IfaceCache::new()) }
31 
32     /// Creates a new factory for single-thread use, where callbacks can mutate their environment.
new_fnmut<D: DataType>() -> Factory<MTFnMut<D>, D>33     pub fn new_fnmut<D: DataType>() -> Factory<MTFnMut<D>, D> { Factory(IfaceCache::new()) }
34 
35     /// Creates a new factory for multi-thread use.
new_sync<D: DataType>() -> Factory<MTSync<D>, D>36     pub fn new_sync<D: DataType>() -> Factory<MTSync<D>, D> { Factory(IfaceCache::new()) }
37 
38 }
39 
40 impl<D: DataType> Factory<MTFn<D>, D> {
41     /// Creates a new method for single-thread use.
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>>42     pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFn<D>, D>
43         where H: 'static + Fn(&MethodInfo<MTFn<D>, D>) -> MethodResult, T: Into<Member<'static>> {
44         super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
45     }
46 }
47 
48 impl<D: DataType> Factory<MTFnMut<D>, D> {
49     /// Creates a new method for single-thread use.
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>>50     pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTFnMut<D>, D>
51         where H: 'static + FnMut(&MethodInfo<MTFnMut<D>, D>) -> MethodResult, T: Into<Member<'static>> {
52         super::leaves::new_method(t.into(), data, Box::new(RefCell::new(handler)) as Box<_>)
53     }
54 }
55 
56 impl<D: DataType> Factory<MTSync<D>, D> {
57     /// Creates a new method for multi-thread use.
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>>58     pub fn method<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<MTSync<D>, D>
59         where H: Fn(&MethodInfo<MTSync<D>, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
60         super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>)
61     }
62 }
63 
64 
65 impl<M: MethodType<D>, D: DataType> Factory<M, D> {
66 
67     /// Creates a new property.
68     ///
69     /// `A` is used to calculate the type signature of the property.
property<A: arg::Arg, T: Into<String>>(&self, name: T, data: D::Property) -> Property<M, D>70     pub fn property<A: arg::Arg, T: Into<String>>(&self, name: T, data: D::Property) -> Property<M, D> {
71         let sig = A::signature();
72         super::leaves::new_property(name.into(), sig, data)
73     }
74 
75     /// Creates a new signal.
signal<T: Into<Member<'static>>>(&self, name: T, data: D::Signal) -> Signal<D>76     pub fn signal<T: Into<Member<'static>>>(&self, name: T, data: D::Signal) -> Signal<D> {
77         super::leaves::new_signal(name.into(), data)
78     }
79 
80     /// Creates a new interface.
interface<T: Into<IfaceName<'static>>>(&self, name: T, data: D::Interface) -> Interface<M, D>81     pub fn interface<T: Into<IfaceName<'static>>>(&self, name: T, data: D::Interface) -> Interface<M, D> {
82         super::objectpath::new_interface(name.into(), data)
83     }
84 
85     /// Creates a new object path.
object_path<T: Into<Path<'static>>>(&self, name: T, data: D::ObjectPath) -> ObjectPath<M, D>86     pub fn object_path<T: Into<Path<'static>>>(&self, name: T, data: D::ObjectPath) -> ObjectPath<M, D> {
87         super::objectpath::new_objectpath(name.into(), data, self.0.clone())
88     }
89 
90     /// Creates a new tree.
tree(&self, data: D::Tree) -> Tree<M, D>91     pub fn tree(&self, data: D::Tree) -> Tree<M, D> {
92         super::objectpath::new_tree(data)
93     }
94 
95     /// Creates a new method - usually you'll use "method" instead.
96     ///
97     /// This is useful for being able to create methods in code which is generic over methodtype.
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>>98     pub fn method_sync<H, T>(&self, t: T, data: D::Method, handler: H) -> Method<M, D>
99     where H: Fn(&MethodInfo<M, D>) -> MethodResult + Send + Sync + 'static, T: Into<Member<'static>> {
100         super::leaves::new_method(t.into(), data, M::make_method(handler))
101     }
102 }
103 
104 
105 #[test]
create_fnmut()106 fn create_fnmut() {
107     let f = Factory::new_fnmut::<()>();
108     let mut move_me = 5u32;
109     let m = f.method("test", (), move |m| {
110         move_me += 1;
111         Ok(vec!(m.msg.method_return().append1(&move_me)))
112     });
113     assert_eq!(&**m.get_name(), "test");
114 }
115 
116 
117 #[test]
fn_customdata()118 fn fn_customdata() {
119     #[derive(Default)]
120     struct Custom;
121     impl DataType for Custom {
122         type Tree = ();
123         type ObjectPath = Arc<u8>;
124         type Interface = ();
125         type Property = ();
126         type Method = i32;
127         type Signal = ();
128     }
129 
130     let f = Factory::new_fn::<Custom>();
131 
132     let m = f.method("test", 789, |_| unimplemented!());
133     assert_eq!(*m.get_data(), 789);
134 
135     let o = f.object_path("/test/test", Arc::new(7));
136     assert_eq!(**o.get_data(), 7);
137 }
138