hypospray 0.1.2

Lightweight dependency injection library
Documentation
use {Co, Component, Construct, Graph, Prototype, Singleton};

pub trait Resolve<'imp, T, K> where T: ?Sized {
    
    type CoImp;
    
    fn __resolve(&'imp self) -> Self::CoImp;
}

impl<'imp, M, T> Resolve<'imp, T, Prototype> for Graph<M>
    where M: ?Sized + Component<T>, 
          T: ?Sized,
          Graph<M>: Dependencies<'imp, Co<M, T>> {
    
    type CoImp = Co<M, T>;
    
    fn __resolve(&'imp self) -> Self::CoImp {
        
        Dependencies::<'imp, Co<M, T>>::__dependencies(self)
    }
}

impl<'imp, M, T> Resolve<'imp, T, Singleton> for Graph<M>
    where M: 'static + ?Sized + Component<T>, 
          T: 'static + ?Sized,
          Graph<M>: Dependencies<'imp, &'imp Co<M, T>> {
    
    type CoImp = &'imp Co<M, T>;
    
    fn __resolve(&'imp self) -> Self::CoImp {
        
        Dependencies::<'imp, &'imp Co<M, T>>::__dependencies(self)
    }
}

pub trait Dependencies<'imp, D> {
    
    fn __dependencies(&'imp self) -> D;
}

impl<'imp, M> Dependencies<'imp, ()> for Graph<M> where M: ?Sized {
    
    fn __dependencies(&'imp self) { }
}

impl<'imp, M, T> Dependencies<'imp, Co<M, T>> for Graph<M>
    where M: ?Sized + Component<T, Scope=Prototype>,
          M::ComponentImp: Construct<'imp>,
          T: ?Sized,
          Graph<M>: Dependencies<'imp, <M::ComponentImp as Construct<'imp>>::Dep> {
    
    fn __dependencies(&'imp self) -> Co<M, T> {
        
        Co(
            <M::ComponentImp as Construct>::__construct(
                self.__dependencies()
            )
        )
    }
}

impl<'imp, M, T> Dependencies<'imp, &'imp Co<M, T>> for Graph<M>
    where M: ?Sized + Component<T, Scope=Singleton>,
          M::ComponentImp: 'static + Send + Construct<'imp>,
          T: 'static + ?Sized,
          Graph<M>: for<'dep> Dependencies<'dep, <M::ComponentImp as Construct<'imp>>::Dep> {
    
    fn __dependencies(&'imp self) -> &'imp Co<M, T> {
        use std::any::TypeId;
        use std::mem;
        use std::sync::MutexGuard;
        use super::{Arc, Container, Shared};
        
        let id = TypeId::of::<T>();
        
        let to_borrowed = |arc: &'imp Arc<Shared>| -> &'imp Co<M, T> {
            let re: &'imp Shared = arc.as_ref();
            let sh: MutexGuard<'imp, _> = re.lock().expect("todo");
            let hash: &Container = &sh;
            let hash = unsafe { mem::transmute::<&Container, &'imp Container>(hash) };
            let dyn: &'imp _ = hash.get(&id).expect("Something unexpected went wrong!");
            
            let co_imp: &'imp M::ComponentImp = dyn
                .downcast_ref::<M::ComponentImp>()
                .expect("Something unexpected went wrong!");
            
            Co::new(co_imp)
        };
        
        let contains = {
            let sh = self.0.lock().expect("todo");
            sh.contains_key(&id)
        };
        
        if contains {
            return to_borrowed(&self.0);
        }
        
        let boxed = Box::new(<M::ComponentImp as Construct>::__construct(self.__dependencies()));
        
        {
            let mut sh = self.0.lock().expect("todo");
            let _ = sh.insert(id, boxed);
        }
        
        to_borrowed(&self.0)
    }
}

macro_rules! deps {
    ($($dep:ident),*) => {
        
        impl<'imp, M, $($dep,)*> Dependencies<'imp, ($($dep,)*)> for Graph<M>
            where M: ?Sized,
                  $(Graph<M>: for<'dep> Dependencies<'dep, $dep>,)* {
                      
            fn __dependencies(&'imp self) -> ($($dep,)*) {
                
                ($(
                    Dependencies::<'imp, $dep>::__dependencies(self),
                )*)
            }
        }
    }
}

deps!(D1, D2);
deps!(D1, D2, D3);
deps!(D1, D2, D3, D4);
deps!(D1, D2, D3, D4, D5);