fluxdi 1.2.0

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

impl Injector {
    pub fn try_resolve<T>(&self) -> Result<Shared<T>, Error>
    where
        T: ?Sized + 'static,
    {
        let type_id = TypeId::of::<T>();
        #[cfg(feature = "tracing")]
        let type_name = std::any::type_name::<T>();
        #[cfg(feature = "tracing")]
        let _span = info_span!(SPAN_RESOLVE, type_name = type_name).entered();

        #[cfg(feature = "metrics")]
        self.inner.metrics.record_resolve_attempt();
        #[cfg(feature = "metrics")]
        let resolve_started = std::time::Instant::now();

        let result = (|| {
            let _guard = ResolveGuard::push(type_id)?;

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "resolve_sync",
                stage = "start",
                "Starting resolve flow"
            );

            if let Some(instance) = self.get_instance::<T>() {
                #[cfg(feature = "tracing")]
                trace!(
                    type_name = type_name,
                    op = "resolve_sync",
                    cache = "hit",
                    "Resolve cache hit"
                );
                #[cfg(feature = "metrics")]
                self.inner.metrics.record_resolve_cache_hit();
                return Ok(instance.value());
            }

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "resolve_sync",
                cache = "miss",
                stage = "create_instance",
                "Resolve cache miss, creating instance"
            );
            #[cfg(feature = "metrics")]
            self.inner.metrics.record_resolve_cache_miss();

            let provider = self.resolve_provider::<T>()?;

            let instance = self.resolve_instance::<T>()?;

            if provider.scope == Scope::Transient {
                #[cfg(feature = "tracing")]
                trace!(
                    type_name = type_name,
                    op = "resolve_sync",
                    scope = %provider.scope,
                    cached = false,
                    "Resolved transient service"
                );
                return Ok(instance.value());
            }

            if let Some(target) = self.cache_target_for_scope(provider.scope) {
                target.store_instance::<T>(instance.clone());
            }

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "resolve_sync",
                scope = %provider.scope,
                cached = true,
                "Resolved and cached service"
            );

            Ok(instance.value())
        })();

        #[cfg(feature = "metrics")]
        match &result {
            Ok(_) => self
                .inner
                .metrics
                .record_resolve_success(resolve_started.elapsed()),
            Err(_) => self
                .inner
                .metrics
                .record_resolve_failure(resolve_started.elapsed()),
        }

        result
    }

    pub fn try_resolve_all<T>(&self) -> Result<Vec<Shared<T>>, Error>
    where
        T: ?Sized + 'static,
    {
        let type_id = TypeId::of::<T>();
        #[cfg(feature = "tracing")]
        let type_name = std::any::type_name::<T>();

        #[cfg(feature = "metrics")]
        self.inner.metrics.record_resolve_attempt();
        #[cfg(feature = "metrics")]
        let resolve_started = std::time::Instant::now();

        #[cfg(feature = "tracing")]
        let _span = info_span!(SPAN_RESOLVE, type_name = type_name, op = "resolve_all").entered();

        let result = (|| {
            let _guard = ResolveGuard::push(type_id)?;

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                op = "resolve_all_sync",
                stage = "start",
                "Resolving service set"
            );

            let providers = self.resolve_set_providers::<T>()?;
            let mut values = Vec::with_capacity(providers.len());

            for (index, provider) in providers.into_iter().enumerate() {
                let cache_target = self.cache_target_for_scope(provider.scope);

                if let Some(target) = &cache_target {
                    if let Some(instance) = target.get_set_instance::<T>(&provider) {
                        #[cfg(feature = "tracing")]
                        trace!(
                            type_name = type_name,
                            op = "resolve_all_sync",
                            index = index,
                            scope = %provider.scope,
                            cache = "hit",
                            "Resolved set item from cache"
                        );
                        #[cfg(feature = "metrics")]
                        self.inner.metrics.record_resolve_cache_hit();
                        values.push(instance.value());
                        continue;
                    }

                    #[cfg(feature = "tracing")]
                    trace!(
                        type_name = type_name,
                        op = "resolve_all_sync",
                        index = index,
                        scope = %provider.scope,
                        cache = "miss",
                        "Set item cache miss, creating instance"
                    );
                    #[cfg(feature = "metrics")]
                    self.inner.metrics.record_resolve_cache_miss();
                }

                let instance = self.resolve_instance_from_provider::<T>(&provider)?;

                if let Some(target) = cache_target {
                    target.store_set_instance::<T>(&provider, instance.clone());
                }

                values.push(instance.value());
            }

            Ok(values)
        })();

        #[cfg(feature = "metrics")]
        match &result {
            Ok(_) => self
                .inner
                .metrics
                .record_resolve_success(resolve_started.elapsed()),
            Err(_) => self
                .inner
                .metrics
                .record_resolve_failure(resolve_started.elapsed()),
        }

        result
    }

    pub fn try_resolve_named<T>(&self, name: &str) -> Result<Shared<T>, Error>
    where
        T: ?Sized + 'static,
    {
        let type_id = TypeId::of::<T>();
        #[cfg(feature = "tracing")]
        let type_name = std::any::type_name::<T>();

        #[cfg(feature = "metrics")]
        self.inner.metrics.record_resolve_attempt();
        #[cfg(feature = "metrics")]
        let resolve_started = std::time::Instant::now();

        #[cfg(feature = "tracing")]
        let _span = info_span!(SPAN_RESOLVE, type_name = type_name, name = %name).entered();

        let result = (|| {
            let _guard = ResolveGuard::push(type_id)?;

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                name = %name,
                op = "resolve_named_sync",
                stage = "start",
                "Resolving named service"
            );

            if let Some(instance) = self.get_instance_named::<T>(name) {
                #[cfg(feature = "tracing")]
                trace!(
                    type_name = type_name,
                    name = %name,
                    op = "resolve_named_sync",
                    cache = "hit",
                    "Named resolve cache hit"
                );
                #[cfg(feature = "metrics")]
                self.inner.metrics.record_resolve_cache_hit();
                return Ok(instance.value());
            }

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                name = %name,
                op = "resolve_named_sync",
                cache = "miss",
                stage = "create_instance",
                "Named resolve cache miss, creating instance"
            );
            #[cfg(feature = "metrics")]
            self.inner.metrics.record_resolve_cache_miss();

            let provider = self.resolve_provider_named::<T>(name)?;
            let instance = self.resolve_instance_named::<T>(name)?;

            if provider.scope == Scope::Transient {
                #[cfg(feature = "tracing")]
                trace!(
                    type_name = type_name,
                    name = %name,
                    op = "resolve_named_sync",
                    scope = %provider.scope,
                    cached = false,
                    "Resolved named transient service"
                );
                return Ok(instance.value());
            }

            if let Some(target) = self.cache_target_for_scope(provider.scope) {
                target.store_instance_named::<T>(name, instance.clone());
            }

            #[cfg(feature = "tracing")]
            trace!(
                type_name = type_name,
                name = %name,
                op = "resolve_named_sync",
                scope = %provider.scope,
                cached = true,
                "Resolved and cached named service"
            );

            Ok(instance.value())
        })();

        #[cfg(feature = "metrics")]
        match &result {
            Ok(_) => self
                .inner
                .metrics
                .record_resolve_success(resolve_started.elapsed()),
            Err(_) => self
                .inner
                .metrics
                .record_resolve_failure(resolve_started.elapsed()),
        }

        result
    }

    pub fn resolve<T>(&self) -> Shared<T>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve::<T>().unwrap()
    }

    pub fn resolve_all<T>(&self) -> Vec<Shared<T>>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve_all::<T>().unwrap()
    }

    pub fn resolve_named<T>(&self, name: &str) -> Shared<T>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve_named::<T>(name).unwrap()
    }

    pub fn optional_resolve<T>(&self) -> Option<Shared<T>>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve::<T>().ok()
    }

    pub fn optional_resolve_all<T>(&self) -> Option<Vec<Shared<T>>>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve_all::<T>().ok()
    }

    pub fn optional_resolve_named<T>(&self, name: &str) -> Option<Shared<T>>
    where
        T: ?Sized + 'static,
    {
        self.try_resolve_named::<T>(name).ok()
    }
}