indep 0.1.1

Depencency injection library for Rust
Documentation
#[macro_export]
macro_rules! indep_pool_async {
    ($base:ty, $($tra:ident),+) => {
        pub enum Implementation {
            $(
            $tra(::std::sync::Arc<::std::sync::RwLock<$tra>>)
            ),+
        }
        
        impl ::std::fmt::Display for Implementation {
            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
                match self {
                    $(&Implementation::$tra(_) => write!(f, "{}", stringify!($tra))),*
                }
            }
        }
        
        pub trait Dependency {
            fn impls(&self) -> Vec<Implementation>;
            fn as_dependent(&self) -> ::std::sync::Arc<::std::sync::RwLock<Dependent>>;
            fn as_base(&self) -> ::std::sync::Arc<::std::sync::RwLock<$base>>;
            fn dep_id(&self) -> &'static str;
        }
        
        pub trait Dependent {
            fn set(&mut self, &Implementation, &Vec<String>);
        }
        
        pub struct Pool {
            deps: Vec<(Vec<String>, Box<Dependency>)>,
        }
        
        impl Pool {
            pub fn new() -> Pool {
                Pool {
                    deps: Vec::new()
                }
            }
            
            pub fn stat(&self) -> String {
                let mut s = String::new();
                
                for &(ref ptags, ref pd) in &self.deps {
                    s.push_str(format!("{}", pd.dep_id()).as_str());
                    if ptags.len() > 0 {
                        s.push_str(" as ");
                        for ptag in ptags {
                            s.push_str(format!("{},", ptag.as_str()).as_str());
                        }
                    }
                    
                    s.push_str(" (");
                    for ref pimp in pd.impls() {
                        s.push_str(format!("{},", pimp).as_str());
                    }
                    s.push_str(") ");
                    
                    s.push_str(" / ");
                }
                
                s
            }
            
            pub fn add(&mut self, ad: Box<Dependency>) {
                self.add_tagged(ad, Vec::with_capacity(0));
            }
            
            pub fn add_tagged(&mut self, ad: Box<Dependency>, atag: Vec<String>) {
                let adc = ad.as_dependent().clone();
                let mut adep = adc.write().unwrap();
            
                for &(ref ptag, ref pd) in &self.deps {
                    let pdc = pd.as_dependent();
                    let mut pdep = pdc.write().unwrap(); 
                    
                    for ref aimp in ad.impls() {
                        pdep.set(aimp, &atag);
                    }
                    
                    for ref pimp in pd.impls() {
                        adep.set(pimp, &ptag);
                    }
                }
                
                self.deps.push((atag, ad));
            } 
        }
    }
}

#[macro_export]
macro_rules! indep_impls_async {
    ($imp:ty, $base:ty, [$($tra:ident),+]) => {
        struct ArcRwLockBox(::std::sync::Arc<::std::sync::RwLock<Box<$imp>>>);
        
        impl Dependency for ArcRwLockBox {
            fn impls(&self) -> Vec<Implementation> {
                vec![
                    $(
                        Implementation::$tra(self.0.clone())
                    ),+
                ]
            }
            fn as_dependent(&self) -> ::std::sync::Arc<::std::sync::RwLock<Dependent>> {
                self.0.clone()
            }
            fn as_base(&self) -> ::std::sync::Arc<::std::sync::RwLock<$base>> {
                self.0.clone()
            }
            fn dep_id(&self) -> &'static str {
                stringify!($imp)
            }
        }
    }
}

#[macro_export]
macro_rules! indep_default_new_async {
    ($imp:ident) => {
        pub fn new_dep() -> Box<Dependency> {
            Box::new(ArcRwLockBox(::std::sync::Arc::new(::std::sync::RwLock::new(Box::new($imp::new())))))
        }
    }
}

#[macro_export]
macro_rules! indep_reqs_async {
    ($imp:ty, [$($tra:ident: [$($id:ident),+]),+]) => {
        impl Dependent for Box<$imp> {
            fn set(&mut self, i: &Implementation, tags: &Vec<String>) {
                match i {
                    $(
                    &Implementation::$tra(ref tr) => {
                        $(
                        if tags.len() < 1 {
                            self.$id = Some(tr.clone());
                            trace!("{} is set to {} as {}", i, stringify!($imp), stringify!($id));
                        } else {
                            for tag in tags {
                                if tag != "" && tag == stringify!($id) {
                                    self.$id = Some(tr.clone());
                                    trace!("{} is set to {} as {}", i, stringify!($imp), stringify!($id));
                                }
                            }
                        }
                        )+
                    }
                    ),+
                    _ => {}
                }
            }
        }
    };
    
    ($imp:ty, []) => {
        impl Dependent for Box<$imp> {
            #[allow(unused_variables)]
            fn set(&mut self, i: &Implementation, tag: &Vec<String>) {}
        }
    }
}

#[cfg(test)]
mod tests {
	 pub mod base {
        pub trait Base {
            fn init(&mut self);
        }
    }
    
    pub mod t1 {
        pub trait Trait1 {
            fn do1(&self);
        }
    }
    
    pub mod t2 {
        pub trait Trait2 {
            fn do2(&self) -> String;
        }
    }
    
    pub mod t3 {
        pub trait Trait3 {
            fn do3(&mut self);
        }
    }
    
    pub mod i1 {
        use super::{Dependency,Dependent,Implementation};
        
        use super::t1::Trait1;
        use super::t2::Trait2;
        
        use std::sync::Arc;
        use std::sync::RwLock;
        use super::base::Base;
        
        struct Impl1;
        
        impl Impl1 {
            pub fn foo(&self) {
                println!("foo from Impl1");
            }
            
            pub fn new() -> Impl1 {
                Impl1
            }
        }
        
        impl Trait1 for Box<Impl1> {
            fn do1(&self) {
                self.foo();
            }
        }
        
        impl Trait2 for Box<Impl1> {
            fn do2(&self) -> String {
                format!("Impl1 says 'Trait2'")
            }
        }
        
        impl Base for Box<Impl1> {
            fn init(&mut self) {
                self.foo();
            }
        }
        
        indep_reqs_async!{Impl1, []}
        indep_impls_async!{Impl1, Base, [Trait1,Trait2]}
        indep_default_new_async!{Impl1}
    }
    
    pub mod i2 {
        use super::{Dependency,Dependent,Implementation};
        
        use super::t1::Trait1;
        use super::t2::Trait2;
        use super::base::Base;
        
        use std::sync::Arc;
        use std::sync::RwLock;
        
        struct Impl2 {
            t1: Option<Arc<RwLock<Trait1>>>
        }
        
        impl Impl2 {
            pub fn boo(&self) {
                println!("boo from Impl2");
                let b = self.t1.as_ref().unwrap();
                b.read().unwrap().do1();
            }
            
            pub fn new() -> Impl2 {
                Impl2 {
                    t1:None
                }
            }
        }
        
        impl Trait2 for Box<Impl2> {
            fn do2(&self) -> String {
                self.boo();
                format!("Impl2 says 'Trait2'")
            }
        }
        
        impl Base for Box<Impl2> {
            fn init(&mut self) {
                self.boo();
            }
        }
        
        indep_reqs_async!{Impl2, [Trait1: [t1]]}
        indep_impls_async!{Impl2, Base, [Trait2]}
        indep_default_new_async!{Impl2}
    }
    
    pub mod i3 {
        use super::{Dependency,Dependent,Implementation};
    
        use super::t3::Trait3;
        use super::t2::Trait2;
        use super::t1::Trait1;
        use super::base::Base;
        
        use std::sync::Arc;
        use std::sync::RwLock;
        
        struct Impl3 {
            t2_1: Option<Arc<RwLock<Trait2>>>,
            t2_2: Option<Arc<RwLock<Trait2>>>,
            t1_1: Option<Arc<RwLock<Trait1>>>
        }
        
        impl Impl3 {
            pub fn oo(&mut self) {
                let b1 = self.t2_1.as_mut().unwrap();
                let b2 = self.t2_2.as_mut().unwrap();
                let b3 = self.t1_1.as_mut().unwrap();
                println!("oo from Impl3: \n1: {}\n2: {}",
                    b1.write().unwrap().do2(),
                    b2.write().unwrap().do2()
                );
                b3.read().unwrap().do1();
            }
            
            pub fn new() -> Impl3 {
                Impl3 {
                    t1_1: None,
                    t2_1: None,
                    t2_2: None,
                }
            }
        }
        
        impl Trait3 for Box<Impl3> {
            fn do3(&mut self) {
                self.oo();
            }
        }
        
        impl Base for Box<Impl3> {
            fn init(&mut self) {
                self.oo();
            }
        }
        
        indep_reqs_async!{Impl3, [Trait1: [t1_1], Trait2: [t2_1,t2_2]]}
        indep_impls_async!{Impl3, Base, [Trait3]}
        indep_default_new_async!{Impl3}
    }
    
    use self::t3::Trait3;
    use self::t2::Trait2;
    use self::t1::Trait1;
    use self::base::Base;
        
    indep_pool_async!{Base, Trait1,Trait2,Trait3}    
    
    #[test]
    fn test_async() {
        let mut pool = Pool::new();
        
        let t1 = i1::new_dep();
        let t2 = i2::new_dep();
        let t3 = i3::new_dep();
        
        pool.add_tagged(t1, vec!["t1_1".to_string()]);
        pool.add(t2);
        pool.add(t3);
        
        println!("Pool stat: {}", pool.stat());
    }
}