Skip to main content

di/description/
descriptor.rs

1use super::ServiceLifetime::{self, *};
2use crate::{Ref, ServiceDependency, ServiceFactory, ServiceProvider, Type};
3use std::any::Any;
4use std::sync::OnceLock;
5
6cfg_if::cfg_if! {
7    if #[cfg(feature = "async")] {
8        macro_rules! service {
9            () => { dyn Any + Send + Sync };
10        }
11    } else {
12        macro_rules! service {
13            () => { dyn Any };
14        }
15    }
16}
17
18/// Represents the description of a service with its service type, implementation, and lifetime.
19pub struct ServiceDescriptor {
20    lifetime: ServiceLifetime,
21    service_type: Type,
22    implementation_type: Type,
23    dependencies: Vec<ServiceDependency>,
24    factory: Ref<ServiceFactory>,
25    instance: Ref<OnceLock<Ref<service!()>>>,
26}
27
28impl ServiceDescriptor {
29    #[cfg(any(feature = "builder", feature = "inject"))]
30    pub(crate) fn new(
31        lifetime: ServiceLifetime,
32        service_type: Type,
33        implementation_type: Type,
34        dependencies: Vec<ServiceDependency>,
35        instance: OnceLock<Ref<service!()>>,
36        factory: Ref<ServiceFactory>,
37    ) -> Self {
38        Self {
39            lifetime,
40            service_type,
41            implementation_type,
42            dependencies,
43            instance: Ref::new(instance),
44            factory,
45        }
46    }
47
48    /// Gets the [lifetime](ServiceLifetime) associated with the service descriptor.
49    #[inline]
50    pub fn lifetime(&self) -> ServiceLifetime {
51        self.lifetime
52    }
53
54    /// Gets the service [type](Type) associated with the service descriptor.
55    #[inline]
56    pub fn service_type(&self) -> &Type {
57        &self.service_type
58    }
59
60    /// Gets the implementation [type](Type) associated with the service descriptor.
61    #[inline]
62    pub fn implementation_type(&self) -> &Type {
63        &self.implementation_type
64    }
65
66    /// Gets the associated [service dependencies](ServiceDependency), if any.
67    #[inline]
68    pub fn dependencies(&self) -> &[ServiceDependency] {
69        &self.dependencies
70    }
71
72    /// Gets or creates the service defined by the service descriptor.
73    ///
74    /// # Arguments
75    ///
76    /// * `services` - The current [service provider](ServiceProvider)
77    pub fn get(&self, services: &ServiceProvider) -> Ref<service!()> {
78        if self.lifetime == Transient {
79            return (self.factory)(services);
80        }
81
82        self.instance.get_or_init(|| (self.factory)(services)).clone()
83    }
84
85    pub(crate) fn clone_with(&self, dependencies: bool) -> Self {
86        Self {
87            lifetime: self.lifetime,
88            service_type: self.service_type.clone(),
89            implementation_type: self.implementation_type.clone(),
90            dependencies: if dependencies {
91                self.dependencies.clone()
92            } else {
93                Vec::new()
94            },
95            instance: if self.lifetime == Singleton {
96                self.instance.clone()
97            } else {
98                Ref::new(OnceLock::new())
99            },
100            factory: self.factory.clone(),
101        }
102    }
103}
104
105impl Clone for ServiceDescriptor {
106    #[inline]
107    fn clone(&self) -> Self {
108        // this might not be 'safe' so always copy dependencies
109        self.clone_with(true)
110    }
111}