pub mod callable;
pub mod component_meta;
pub mod expander;
pub mod injection_binder;
pub mod injector;
pub mod tags;

pub use mydi_macros::Component;
pub use mydi_macros::ComponentExpander;

pub type Injector = injector::Injector;
pub type InjectionBinder<T> = injection_binder::InjectionBinder<T>;

pub type Lazy<T> = std::sync::Arc<std::sync::LazyLock<T, Box<dyn FnOnce() -> T>>>;

impl<T: Clone + 'static> crate::component_meta::ComponentMeta for Lazy<T> {
    fn inject(injector: &crate::injector::Injector) -> anyhow::Result<Self> {
        use std::sync::Arc;
        let injector = injector.clone();
        let func: Box<dyn FnOnce() -> T + 'static> = Box::new(move || -> T {
            match injector.get::<T>() {
                Ok(x) => x,
                _ => unreachable!(),
            }
        });
        let result = std::sync::LazyLock::new(func);
        Ok(Arc::new(result))
    }

    fn debug_line() -> Option<String> {
        None
    }

    fn dependencies_names() -> Vec<(std::any::TypeId, &'static str)> {
        vec![(std::any::TypeId::of::<T>(), std::any::type_name::<T>())]
    }

    fn lazy() -> bool {
        true
    }
}

#[macro_export]
macro_rules! erase {
    ( $pointer:ident < $dyn_type:ty > ) => {{
        |x| -> $pointer<$dyn_type> { $pointer::new(x) }
    }};
}
