fluxdi 1.2.2

FluxDI - Semi-Automatic Dependency Injector
Documentation
use super::*;

impl Injector {
    pub(crate) fn get_provider<T>(&self) -> Option<Shared<dyn Any + Send + Sync>>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        let type_id = TypeId::of::<T>();
        #[cfg(feature = "tracing")]
        let type_name = std::any::type_name::<T>();

        #[cfg(feature = "lock-free")]
        let local = self
            .inner
            .providers
            .get(&type_id)
            .map(|value| value.value().clone());
        #[cfg(not(feature = "lock-free"))]
        let local = self.inner.providers.read().unwrap().get(&type_id).cloned();

        if local.is_some() {
            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "provider_lookup",
                source = "local",
                hit = true,
                "Provider lookup hit"
            );
            return local;
        }

        #[cfg(feature = "tracing")]
        trace!(
            type_name = type_name,
            op = "provider_lookup",
            source = "local",
            hit = false,
            has_parent = self.inner.parent.is_some(),
            "Provider lookup miss"
        );

        if let Some(parent) = &self.inner.parent {
            let parent_injector = Injector {
                inner: parent.clone(),
            };

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "provider_lookup",
                source = "parent",
                "Falling back to parent injector"
            );

            return parent_injector.get_provider::<T>();
        }

        #[cfg(feature = "tracing")]
        trace!(
            type_name = type_name,
            op = "provider_lookup",
            source = "none",
            "Provider not found in injector hierarchy"
        );

        None
    }

    pub(crate) fn get_provider_named<T>(&self, name: &str) -> Option<Shared<dyn Any + Send + Sync>>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        let key = NamedTypeKey::of::<T>(name);
        #[cfg(feature = "tracing")]
        let type_name = std::any::type_name::<T>();

        #[cfg(feature = "lock-free")]
        let local = self
            .inner
            .named_providers
            .get(&key)
            .map(|value| value.value().clone());
        #[cfg(not(feature = "lock-free"))]
        let local = self
            .inner
            .named_providers
            .read()
            .unwrap()
            .get(&key)
            .cloned();

        if local.is_some() {
            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                name = %name,
                op = "provider_lookup_named",
                source = "local",
                hit = true,
                "Named provider lookup hit"
            );
            return local;
        }

        #[cfg(feature = "tracing")]
        trace!(
            type_name = type_name,
            name = %name,
            op = "provider_lookup_named",
            source = "local",
            hit = false,
            has_parent = self.inner.parent.is_some(),
            "Named provider lookup miss"
        );

        if let Some(parent) = &self.inner.parent {
            let parent_injector = Injector {
                inner: parent.clone(),
            };

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                name = %name,
                op = "provider_lookup_named",
                source = "parent",
                "Falling back to parent injector for named provider"
            );

            return parent_injector.get_provider_named::<T>(name);
        }

        #[cfg(feature = "tracing")]
        trace!(
            type_name = type_name,
            name = %name,
            op = "provider_lookup_named",
            source = "none",
            "Named provider not found in injector hierarchy"
        );

        None
    }

    pub(crate) fn resolve_provider<T>(&self) -> Result<Shared<Provider<T>>, Error>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        let type_name = std::any::type_name::<T>();

        let any_provider = self
            .get_provider::<T>()
            .ok_or_else(|| Error::service_not_provided(type_name))?;

        let provider = any_provider
            .downcast::<Provider<T>>()
            .map_err(|_| Error::type_mismatch(type_name))?;

        #[cfg(feature = "tracing")]
        debug!(
            type_name = type_name,
            op = "provider_resolve",
            "Resolved provider metadata"
        );

        Ok(provider)
    }

    pub(crate) fn resolve_provider_named<T>(&self, name: &str) -> Result<Shared<Provider<T>>, Error>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        let type_name = std::any::type_name::<T>();

        let any_provider = self
            .get_provider_named::<T>(name)
            .ok_or_else(|| Error::service_not_provided_named(type_name, name))?;

        let provider = any_provider
            .downcast::<Provider<T>>()
            .map_err(|_| Error::type_mismatch(type_name))?;

        #[cfg(feature = "tracing")]
        debug!(
            type_name = type_name,
            name = %name,
            op = "provider_resolve_named",
            "Resolved named provider metadata"
        );

        Ok(provider)
    }

    pub(crate) fn collect_set_providers<T>(
        &self,
        providers: &mut Vec<Shared<Provider<T>>>,
    ) -> Result<(), Error>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        if let Some(parent) = &self.inner.parent {
            let parent_injector = Injector {
                inner: parent.clone(),
            };
            parent_injector.collect_set_providers::<T>(providers)?;
        }

        let type_id = TypeId::of::<T>();
        let type_name = std::any::type_name::<T>();

        #[cfg(feature = "lock-free")]
        let local = self
            .inner
            .set_providers
            .get(&type_id)
            .map(|value| value.value().clone())
            .unwrap_or_default();
        #[cfg(not(feature = "lock-free"))]
        let local = self
            .inner
            .set_providers
            .read()
            .unwrap()
            .get(&type_id)
            .cloned()
            .unwrap_or_default();
        #[cfg_attr(not(feature = "tracing"), allow(unused_variables))]
        let local_count = local.len();

        for any_provider in local {
            let provider = any_provider
                .downcast::<Provider<T>>()
                .map_err(|_| Error::type_mismatch(type_name))?;
            providers.push(provider);
        }

        #[cfg(feature = "tracing")]
        trace!(
            type_name = type_name,
            op = "provider_collect_set",
            local_count = local_count,
            aggregate_count = providers.len(),
            "Collected set providers from injector node"
        );

        Ok(())
    }

    pub(crate) fn resolve_set_providers<T>(&self) -> Result<Vec<Shared<Provider<T>>>, Error>
    where
        T: ?Sized + Send + Sync + 'static,
    {
        let type_name = std::any::type_name::<T>();
        let mut providers = Vec::new();
        self.collect_set_providers::<T>(&mut providers)?;

        if providers.is_empty() {
            return Err(Error::service_not_provided(type_name));
        }

        #[cfg(feature = "tracing")]
        debug!(
            type_name = type_name,
            op = "provider_resolve_set",
            provider_count = providers.len(),
            "Resolved provider set"
        );

        Ok(providers)
    }
}