chassis 0.2.0

Compile-time dependency injection framework
Documentation
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;

macro_rules! instance_counter_cls {
    ($name:ident, $instances_name:ident) => {
        static $instances_name: AtomicUsize = AtomicUsize::new(0);

        pub struct $name {
            instance: usize,
        }

        impl $name {
            pub fn new() -> Self {
                Self {
                    instance: $instances_name.fetch_add(1, Ordering::SeqCst),
                }
            }

            pub fn instance(&self) -> usize {
                self.instance
            }

            pub fn instances() -> usize {
                $instances_name.load(Ordering::SeqCst)
            }
        }
    };
}

instance_counter_cls!(InstanceCounterDep, INSTANCES_DEP);
instance_counter_cls!(InstanceCounter1, INSTANCES_1);
instance_counter_cls!(InstanceCounter2, INSTANCES_2);

#[derive(Default)]
pub struct TestProvider;

#[chassis::module]
impl TestProvider {
    #[chassis(singleton)]
    pub fn provide_singleton() -> Arc<InstanceCounterDep> {
        Arc::new(InstanceCounterDep::new())
    }

    #[chassis(singleton)]
    pub fn provide_singleton2() -> Arc<InstanceCounter2> {
        Arc::new(InstanceCounter2::new())
    }

    #[chassis(singleton)]
    pub fn provide_singleton1(_dep: Arc<InstanceCounter2>) -> Arc<InstanceCounter1> {
        Arc::new(InstanceCounter1::new())
    }
}

#[chassis::injector(modules = [TestProvider])]
pub trait TestFactory {
    fn provide_singleton(&self) -> Arc<InstanceCounterDep>;
    fn provide_singleton1(&self) -> Arc<InstanceCounter1>;
    fn provide_singleton2(&self) -> Arc<InstanceCounter2>;
}

#[test]
fn check_dep() {
    let injector = <dyn TestFactory>::new().unwrap();
    injector.provide_singleton();
    injector.provide_singleton();
    let singleton = injector.provide_singleton();

    assert_eq!(0, singleton.instance());
    assert_eq!(1, InstanceCounterDep::instances());
}

#[test]
fn check_multiple() {
    let injector = <dyn TestFactory>::new().unwrap();
    injector.provide_singleton1();
    injector.provide_singleton2();
    let singleton = injector.provide_singleton2();

    assert_eq!(0, singleton.instance());
    assert_eq!(1, InstanceCounter1::instances());
    assert_eq!(1, InstanceCounter2::instances());
}