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, D: DataType=()>(Arc>); impl, D: DataType> From>> for Factory { fn from(f: Arc>) -> Self { Factory(f) } } impl Factory, ()> { /// Creates a new factory for single-thread use. pub fn new_fn() -> Factory, D> { Factory(IfaceCache::new()) } /// Creates a new factory for single-thread use, where callbacks can mutate their environment. pub fn new_fnmut() -> Factory, D> { Factory(IfaceCache::new()) } /// Creates a new factory for multi-thread use. pub fn new_sync() -> Factory, D> { Factory(IfaceCache::new()) } } impl Factory, D> { /// Creates a new method for single-thread use. pub fn method(&self, t: T, data: D::Method, handler: H) -> Method, D> where H: 'static + Fn(&MethodInfo, D>) -> MethodResult, T: Into> { super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>) } } impl Factory, D> { /// Creates a new method for single-thread use. pub fn method(&self, t: T, data: D::Method, handler: H) -> Method, D> where H: 'static + FnMut(&MethodInfo, D>) -> MethodResult, T: Into> { super::leaves::new_method(t.into(), data, Box::new(RefCell::new(handler)) as Box<_>) } } impl Factory, D> { /// Creates a new method for multi-thread use. pub fn method(&self, t: T, data: D::Method, handler: H) -> Method, D> where H: Fn(&MethodInfo, D>) -> MethodResult + Send + Sync + 'static, T: Into> { super::leaves::new_method(t.into(), data, Box::new(handler) as Box<_>) } } impl, D: DataType> Factory { /// Creates a new property. /// /// `A` is used to calculate the type signature of the property. pub fn property>(&self, name: T, data: D::Property) -> Property { let sig = A::signature(); super::leaves::new_property(name.into(), sig, data) } /// Creates a new signal. pub fn signal>>(&self, name: T, data: D::Signal) -> Signal { super::leaves::new_signal(name.into(), data) } /// Creates a new interface. pub fn interface>>(&self, name: T, data: D::Interface) -> Interface { super::objectpath::new_interface(name.into(), data) } /// Creates a new object path. pub fn object_path>>(&self, name: T, data: D::ObjectPath) -> ObjectPath { super::objectpath::new_objectpath(name.into(), data, self.0.clone()) } /// Creates a new tree. pub fn tree(&self, data: D::Tree) -> Tree { 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(&self, t: T, data: D::Method, handler: H) -> Method where H: Fn(&MethodInfo) -> MethodResult + Send + Sync + 'static, T: Into> { 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; type Interface = (); type Property = (); type Method = i32; type Signal = (); } let f = Factory::new_fn::(); 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); }