1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
use crate::{Mut, ServiceDependency, ServiceProvider, Type};
use spin::Once;
use std::any::Any;
/// Represents the possible service lifetimes.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum ServiceLifetime {
/// Indicates that a single instance of the service will be created.
Singleton,
/// Indicates that a new instance of the service will be created for each scope.
Scoped,
/// Indicates that a new instance of the service will be created every time it is requested.
Transient,
}
/// Represents the type alias for a service reference.
#[cfg(not(feature = "async"))]
pub type Ref<T> = std::rc::Rc<T>;
/// Represents the type alias for a service reference.
#[cfg(feature = "async")]
pub type Ref<T> = std::sync::Arc<T>;
/// Represents the type alias for a mutable service reference.
pub type RefMut<T> = Ref<Mut<T>>;
/// Represents the callback function used to create a service.
pub type ServiceFactory = dyn Fn(&ServiceProvider) -> Ref<dyn Any>;
/// Represents the description of a service with its service type, implementation, and lifetime.
pub struct ServiceDescriptor {
lifetime: ServiceLifetime,
service_type: Type,
implementation_type: Type,
dependencies: Vec<ServiceDependency>,
instance: Ref<Once<Ref<dyn Any>>>,
factory: Ref<ServiceFactory>,
}
impl ServiceDescriptor {
#[cfg(any(feature = "builder", feature = "inject"))]
pub(crate) fn new(
lifetime: ServiceLifetime,
service_type: Type,
implementation_type: Type,
dependencies: Vec<ServiceDependency>,
instance: Once<Ref<dyn Any>>,
factory: Ref<ServiceFactory>,
) -> Self {
Self {
lifetime,
service_type,
implementation_type,
dependencies,
instance: Ref::new(instance),
factory,
}
}
/// Gets the [lifetime](crate::ServiceLifetime) associated with the service descriptor.
pub fn lifetime(&self) -> ServiceLifetime {
self.lifetime
}
/// Gets the service [type](crate::Type) associated with the service descriptor.
pub fn service_type(&self) -> &Type {
&self.service_type
}
/// Gets the implementation [type](crate::Type) associated with the service descriptor.
pub fn implementation_type(&self) -> &Type {
&self.implementation_type
}
/// Gets the associated [service dependencies](crate::ServiceDependency), if any.
pub fn dependencies(&self) -> &[ServiceDependency] {
&self.dependencies
}
/// Gets or creates the service defined by the service descriptor.
///
/// # Arguments
///
/// * `services` - The current [`ServiceProvider`](crate::ServiceProvider)
pub fn get(&self, services: &ServiceProvider) -> Ref<dyn Any> {
if self.lifetime == ServiceLifetime::Transient {
return (self.factory)(services);
}
return self.instance.call_once(|| (self.factory)(services)).clone();
}
pub(crate) fn clone_with(&self, dependencies: bool) -> Self {
Self {
lifetime: self.lifetime,
service_type: self.service_type.clone(),
implementation_type: self.implementation_type.clone(),
dependencies: if dependencies {
self.dependencies.clone()
} else {
Vec::with_capacity(0)
},
instance: if self.lifetime == ServiceLifetime::Singleton {
self.instance.clone()
} else {
Ref::new(Once::new())
},
factory: self.factory.clone(),
}
}
}
impl Clone for ServiceDescriptor {
fn clone(&self) -> Self {
// without context, we don't know if this is 'safe';
// always copy dependencies here
self.clone_with(true)
}
}