use crate::entry::{
AsyncServiceFactory, KeyedServiceFactory, ServiceDescriptor, ServiceFactory, ServiceLifetime,
};
use crate::key::ServiceKey;
use crate::registration::ServiceRegistration;
use std::any::Any;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
pub struct ServiceCollection {
descriptors: Vec<ServiceDescriptor>,
}
impl ServiceCollection {
pub fn new() -> Self {
Self {
descriptors: Vec::new(),
}
}
pub fn singleton<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push(ServiceLifetime::Singleton, None, f);
self
}
pub fn transient<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push(ServiceLifetime::Transient, None, f);
self
}
pub fn scoped<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push(ServiceLifetime::Scoped, None, f);
self
}
pub fn keyed_singleton<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_keyed(ServiceLifetime::Singleton, k.into(), f);
self
}
pub fn keyed_transient<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_keyed(ServiceLifetime::Transient, k.into(), f);
self
}
pub fn keyed_scoped<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_keyed(ServiceLifetime::Scoped, k.into(), f);
self
}
pub fn keyed_any_singleton<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver, &ServiceKey) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_any_keyed(ServiceLifetime::Singleton, f);
self
}
pub fn keyed_any_scoped<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver, &ServiceKey) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_any_keyed(ServiceLifetime::Scoped, f);
self
}
pub fn keyed_any_transient<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(&dyn crate::entry::IServiceResolver, &ServiceKey) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push_any_keyed(ServiceLifetime::Transient, f);
self
}
pub fn async_singleton<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Singleton, None, f);
self
}
pub fn async_transient<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Transient, None, f);
self
}
pub fn async_scoped<T: ?Sized + Send + Sync + 'static>(
mut self,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Scoped, None, f);
self
}
pub fn async_keyed_singleton<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Singleton, Some(k.into()), f);
self
}
pub fn async_keyed_transient<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Transient, Some(k.into()), f);
self
}
pub fn async_keyed_scoped<T: ?Sized + Send + Sync + 'static>(
mut self,
k: impl Into<ServiceKey>,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) -> Self {
self.push_async(ServiceLifetime::Scoped, Some(k.into()), f);
self
}
pub fn try_add<T: ?Sized + Send + Sync + 'static>(
self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.try_add_with_lifetime(ServiceLifetime::Singleton, f)
}
pub fn try_add_singleton<T: ?Sized + Send + Sync + 'static>(
self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.try_add_with_lifetime(ServiceLifetime::Singleton, f)
}
pub fn try_add_scoped<T: ?Sized + Send + Sync + 'static>(
self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.try_add_with_lifetime(ServiceLifetime::Scoped, f)
}
pub fn try_add_transient<T: ?Sized + Send + Sync + 'static>(
self,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.try_add_with_lifetime(ServiceLifetime::Transient, f)
}
fn try_add_with_lifetime<T: ?Sized + Send + Sync + 'static>(
mut self,
lt: ServiceLifetime,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
let tid = std::any::TypeId::of::<T>();
if self
.descriptors
.iter()
.any(|d| d.type_id == tid && d.key.is_none())
{
return self;
}
self.push(lt, None, f);
self
}
pub fn add<T: ?Sized + Send + Sync + 'static>(
mut self,
lt: ServiceLifetime,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) -> Self {
self.push(lt, None, f);
self
}
pub fn instance<T: Send + Sync + 'static>(mut self, v: Arc<T>) -> Self {
let ff: ServiceFactory = Arc::new(move |_| Arc::new(v.clone()));
self.descriptors.push(ServiceDescriptor {
type_id: std::any::TypeId::of::<T>(),
type_name: std::any::type_name::<T>(),
key: None,
factory: ff,
keyed_factory: None,
async_factory: None,
lifetime: ServiceLifetime::Singleton,
});
self
}
pub fn singleton_value<T: Send + Sync + 'static>(self, v: T) -> Self {
self.instance(Arc::new(v))
}
pub fn build(self) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
self.build_with(crate::provider::ServiceProviderOptions::default())
}
pub fn build_with(
self,
options: crate::provider::ServiceProviderOptions,
) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
crate::provider::ServiceProvider::new_with(self.into_store(), options)
}
pub async fn build_async(
self,
) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
self.build_async_with(crate::provider::ServiceProviderOptions::default())
.await
}
pub async fn build_async_with(
self,
options: crate::provider::ServiceProviderOptions,
) -> Result<Arc<crate::provider::ServiceProvider>, crate::error::RdiError> {
crate::provider::ServiceProvider::new_async_with(self.into_store(), options).await
}
fn into_store(self) -> crate::entry::ServiceStore {
let mut s = crate::entry::ServiceStore::new();
for (n, d) in self.descriptors.into_iter().enumerate() {
let e = crate::entry::ServiceEntry {
cache_key: n,
key: d.key,
type_name: d.type_name,
factory: d.factory,
keyed_factory: d.keyed_factory,
async_factory: d.async_factory,
lifetime: d.lifetime,
};
s.entry(d.type_id).or_default().push(e);
}
s
}
#[cfg(any(target_os = "linux", target_os = "macos", target_os = "windows"))]
pub fn from_injected() -> Self {
let mut descriptors = Vec::new();
for reg in inventory::iter::<ServiceRegistration> {
let factory: ServiceFactory = Arc::new(move |r| (reg.factory)(r));
descriptors.push(ServiceDescriptor {
type_id: reg.type_id,
type_name: (reg.type_name_fn)(),
key: None,
factory,
keyed_factory: None,
async_factory: None,
lifetime: reg.lifetime,
});
}
Self { descriptors }
}
fn push<T: ?Sized + Send + Sync + 'static>(
&mut self,
lt: ServiceLifetime,
key: Option<ServiceKey>,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) {
let sf: ServiceFactory = Arc::new(move |r| {
let val: Arc<T> = (f)(r);
Arc::new(val) as Arc<dyn Any + Send + Sync>
});
self.descriptors.push(ServiceDescriptor {
type_id: std::any::TypeId::of::<T>(),
type_name: std::any::type_name::<T>(),
key,
factory: sf,
keyed_factory: None,
async_factory: None,
lifetime: lt,
});
}
fn push_keyed<T: ?Sized + Send + Sync + 'static>(
&mut self,
lt: ServiceLifetime,
key: ServiceKey,
f: impl Fn(&dyn crate::entry::IServiceResolver) -> Arc<T> + Send + Sync + 'static,
) {
self.push(lt, Some(key), f);
}
fn push_any_keyed<T: ?Sized + Send + Sync + 'static>(
&mut self,
lt: ServiceLifetime,
f: impl Fn(&dyn crate::entry::IServiceResolver, &ServiceKey) -> Arc<T> + Send + Sync + 'static,
) {
let keyed: KeyedServiceFactory = Arc::new(move |r, key| {
let val: Arc<T> = (f)(r, key);
Arc::new(val) as Arc<dyn Any + Send + Sync>
});
let stub: ServiceFactory = Arc::new(|_| {
std::panic::panic_any(crate::error::RdiError::FactoryPanic {
service: "AnyKey registration".into(),
payload: "AnyKey registrations require a requested key and cannot be \
resolved without one"
.into(),
})
});
self.descriptors.push(ServiceDescriptor {
type_id: std::any::TypeId::of::<T>(),
type_name: std::any::type_name::<T>(),
key: Some(ServiceKey::any_key()),
factory: stub,
keyed_factory: Some(keyed),
async_factory: None,
lifetime: lt,
});
}
fn push_async<T: ?Sized + Send + Sync + 'static>(
&mut self,
lt: ServiceLifetime,
key: Option<ServiceKey>,
f: impl Fn(
Arc<crate::provider::ServiceProvider>,
) -> Pin<Box<dyn Future<Output = Arc<T>> + Send>>
+ Send
+ Sync
+ 'static,
) {
let af: AsyncServiceFactory = Arc::new(move |sp: Arc<crate::provider::ServiceProvider>| {
let fut = (f)(sp);
Box::pin(async move {
let val: Arc<T> = fut.await;
Arc::new(val) as Arc<dyn Any + Send + Sync>
}) as Pin<Box<dyn Future<Output = Arc<dyn Any + Send + Sync>> + Send>>
});
let type_name = std::any::type_name::<T>();
let sf: ServiceFactory = Arc::new(move |_| {
std::panic::panic_any(crate::error::RdiError::AsyncServiceRequiresGetAsync {
service: type_name.to_string(),
})
});
self.descriptors.push(ServiceDescriptor {
type_id: std::any::TypeId::of::<T>(),
type_name,
key,
factory: sf,
keyed_factory: None,
async_factory: Some(af),
lifetime: lt,
});
}
}
impl Default for ServiceCollection {
fn default() -> Self {
Self::new()
}
}