Skip to main content

kabel/
lib.rs

1#[cfg(feature = "axum")]
2pub mod axum;
3pub mod error;
4#[cfg(feature = "jav")]
5pub mod jav;
6pub mod scope;
7
8use std::{
9	any::{Any, TypeId},
10	sync::{Arc, OnceLock},
11};
12
13use arc_swap::ArcSwapOption;
14use scc::HashMap;
15
16use crate::{
17	error::{ServiceAlreadyExistsError, ServiceNotFoundError},
18	scope::{Scope, ScopeProvider, get_default_scope_full},
19};
20
21pub struct DI<T: Send + Sync + 'static>(pub Arc<T>);
22pub struct DIK<T: Send + Sync + 'static, K: 'static>(pub Arc<T>, std::marker::PhantomData<K>);
23
24#[derive(Clone)]
25pub enum Service {
26	Singleton(Arc<dyn Any + Send + Sync>),
27	Transient(Arc<dyn Fn() -> Arc<dyn Any + Send + Sync> + Send + Sync>),
28	Scoped(Arc<dyn Fn() -> Arc<dyn Any + Send + Sync> + Send + Sync>),
29}
30
31#[derive(Clone)]
32pub struct ServiceCollection {
33	collection: HashMap<(TypeId, Option<TypeId>), Service>,
34}
35
36impl ServiceCollection {
37	pub fn new() -> Self {
38		Self {
39			collection: HashMap::new(),
40		}
41	}
42
43	pub fn add_singleton<T: Send + Sync + 'static>(
44		&self,
45		service: T,
46	) -> Result<(), ServiceAlreadyExistsError> {
47		self.add_internal::<T>(Service::Singleton(Arc::new(service)), None)
48	}
49	pub fn add_singleton_keyed<T: Send + Sync + 'static>(
50		&self,
51		service: T,
52		key: TypeId,
53	) -> Result<(), ServiceAlreadyExistsError> {
54		self.add_internal::<T>(Service::Singleton(Arc::new(service)), Some(key))
55	}
56
57	fn add_internal<T: Send + Sync + 'static>(
58		&self,
59		service: Service,
60		key: Option<TypeId>,
61	) -> Result<(), ServiceAlreadyExistsError> {
62		let tid = (TypeId::of::<T>(), key);
63		if self.collection.contains_sync(&tid) {
64			return Err(ServiceAlreadyExistsError);
65		}
66		self.collection.insert_sync(tid, service);
67		Ok(())
68	}
69
70	pub fn add_transient<T: Send + Sync + 'static, F>(
71		&self,
72		service_factory: F,
73	) -> Result<(), ServiceAlreadyExistsError>
74	where
75		F: Fn() -> T + Send + Sync + 'static,
76	{
77		self.add_internal::<T>(
78			Service::Transient(Arc::new(move || Arc::new(service_factory()))),
79			None,
80		)
81	}
82	pub fn add_transient_keyed<T: Send + Sync + 'static, F>(
83		&self,
84		service_factory: F,
85		key: TypeId,
86	) -> Result<(), ServiceAlreadyExistsError>
87	where
88		F: Fn() -> T + Send + Sync + 'static,
89	{
90		self.add_internal::<T>(
91			Service::Transient(Arc::new(move || Arc::new(service_factory()))),
92			Some(key),
93		)
94	}
95
96	pub fn add_scoped<T: Send + Sync + 'static, F>(
97		&self,
98		service_factory: F,
99	) -> Result<(), ServiceAlreadyExistsError>
100	where
101		F: Fn() -> T + Send + Sync + 'static,
102	{
103		self.add_internal::<T>(
104			Service::Scoped(Arc::new(move || Arc::new(service_factory()))),
105			None,
106		)
107	}
108	pub fn add_scoped_keyed<T: Send + Sync + 'static, F>(
109		&self,
110		service_factory: F,
111		key: TypeId,
112	) -> Result<(), ServiceAlreadyExistsError>
113	where
114		F: Fn() -> T + Send + Sync + 'static,
115	{
116		self.add_internal::<T>(
117			Service::Scoped(Arc::new(move || Arc::new(service_factory()))),
118			Some(key),
119		)
120	}
121
122	pub fn create_scope(&self) -> Arc<Scope> {
123		let scope: Scope = HashMap::new();
124		self.collection.iter_sync(|k, v| {
125			let Service::Scoped(_) = v else {
126				return true;
127			};
128			scope.insert_sync(k.clone(), OnceLock::new());
129			true
130		});
131		Arc::new(scope)
132	}
133
134	fn di_internal<T: Send + Sync + 'static>(
135		&self,
136		key: Option<TypeId>,
137		scope: Option<Arc<Arc<dyn ScopeProvider>>>,
138	) -> Result<Arc<T>, ServiceNotFoundError> {
139		let tid = (TypeId::of::<T>(), key);
140		if let Some(s) = self.collection.read_sync(&tid, |_, s| match s {
141			Service::Singleton(service) if let Ok(res) = service.clone().downcast() => Ok(res),
142			Service::Transient(factory) if let Ok(res) = factory.clone()().downcast() => Ok(res),
143			Service::Scoped(factory) => {
144				let scope = scope
145					.unwrap_or_else(|| get_default_scope_full())
146					.provide_scope()?;
147				let Some(res) = scope.get_sync(&tid) else {
148					return Err(ServiceNotFoundError);
149				};
150				res.get_or_init(|| factory.clone()())
151					.clone()
152					.downcast()
153					.map_err(|_| ServiceNotFoundError)
154			},
155			_ => Err(ServiceNotFoundError),
156		}) {
157			return s;
158		} else {
159			Err(ServiceNotFoundError)
160		}
161	}
162
163	pub fn di<T: Send + Sync + 'static>(&self) -> Result<Arc<T>, ServiceNotFoundError> {
164		self.di_internal(None, None)
165	}
166
167	pub fn dik<T: Send + Sync + 'static, K: 'static>(
168		&self,
169	) -> Result<Arc<T>, ServiceNotFoundError> {
170		self.di_internal(Some(TypeId::of::<K>()), None)
171	}
172
173	pub fn dis<T: Send + Sync + 'static>(
174		&self,
175		scope: Arc<Arc<dyn ScopeProvider>>,
176	) -> Result<Arc<T>, ServiceNotFoundError> {
177		self.di_internal(None, Some(scope))
178	}
179	pub fn disk<T: Send + Sync + 'static, K: 'static>(
180		&self,
181		scope: Arc<Arc<dyn ScopeProvider>>,
182	) -> Result<Arc<T>, ServiceNotFoundError> {
183		self.di_internal(Some(TypeId::of::<K>()), Some(scope))
184	}
185}
186
187static SERVICE_PROVIDER: ArcSwapOption<ServiceCollection> = ArcSwapOption::const_empty();
188
189pub fn sp() -> Option<Arc<ServiceCollection>> {
190	SERVICE_PROVIDER.load_full()
191}
192
193pub fn spp() -> Arc<ServiceCollection> {
194	sp().expect("ServiceProvider not yet initialized")
195}
196
197pub fn set_sp(sp: ServiceCollection) -> Option<Arc<ServiceCollection>> {
198	set_sp_arc(Arc::new(sp))
199}
200pub fn set_sp_arc(sp: Arc<ServiceCollection>) -> Option<Arc<ServiceCollection>> {
201	SERVICE_PROVIDER.swap(Some(sp))
202}