singleton_manager/lib.rs
1//! # Singleton Manager
2//! A singleton manger for handling and holding singletons in a system
3//!
4//! ## build Purpose
5//! This was build because of multiple minor libraries that was either using `lazy_static!` or other
6//! macros to handle late initializations of singletons in system.
7//!
8//! Example of such libraries
9//!
10//! 1. Database Pool Manager, that though out the entire services lifetime needs to continue running to track the number of active connections.
11//! 2. Logging, a logging library that collects and tracks calls through out the entire execution of a single thread, for then later to flush all the logs as a collection of a single request.
12//! 3. Worker Queue system, a worker queue system that needs to track each individual execution, and where new executions can be dynamically added to it while running.
13//!
14//! Previously the applications were using `lazy_static!` but `lazy_static!` is using `unsafe` modify
15//! on each activation. To reduce the failurepoints this system is also using `unsafe` but only in
16//! one place to minimize impact, on top of that it is programmatically accessible and modifiable.
17//! Allowing you to create object on the fly when needed.
18//!
19//!
20//! A full example of how to use this:
21//! ```
22//! use singleton_manager::sm;
23//! use std::sync::Mutex;
24//!
25//! pub struct MyService {
26//! message: String,
27//! guard: Mutex<()>,
28//! }
29//!
30//! impl MyService {
31//! pub fn set(&mut self, msg: &str) {
32//! let mut _guard = self.guard.lock().expect("Failed to get guard");
33//! self.message = msg.to_string();
34//! }
35//!
36//! pub fn get(&self) -> String {
37//! let _guard = self.guard.lock();
38//! self.message.clone()
39//! }
40//! }
41//!
42//! sm().set("my_service",
43//! MyService {
44//! message: "".to_string(),
45//! guard: Mutex::new(()),
46//! }).ok();
47//!
48//! let service = sm()
49//! .get::<MyService>("my_service")
50//! .expect("Failed to get service");
51//! service.set("My Message");
52//!
53//! let different_service = sm()
54//! .get::<MyService>("my_service")
55//! .expect("Failed to get service");
56//!
57//!assert_eq!("My Message".to_string(), different_service.get());
58//! ```
59extern crate uuid;
60
61use std::any::Any;
62use std::cell::Cell;
63use std::collections::HashMap;
64use std::fmt::{Debug, Display, Formatter};
65use std::ops::DerefMut;
66use std::sync::Once;
67use uuid::Uuid;
68
69static mut INSTANCE: Cell<Option<SingletonManager>> = Cell::new(None);
70static mut ONCE: Once = Once::new();
71
72/// Common Result used in the library.
73pub type Result<T> = std::result::Result<T, Error>;
74
75#[derive(Debug, Clone)]
76pub enum Error {
77 ServiceDoesNotExist(String),
78 ServiceNotInstantiated(String),
79 FailedToDowncastRefOfService(String),
80 FailedToStoreService(String),
81 NoFactoryFunctionAvailable(String),
82 SetFailedToReturnAServiceReference(String),
83 FailedToDowncastFactoryOutput(String),
84 NoServiceWithStorageRequest,
85 FailedToStoreServiceAlias,
86 MutexGotPoison,
87 ServiceAlreadyExists,
88 FailedToStoreFactory,
89 UnknownError(String),
90}
91
92impl From<String> for Error {
93 fn from(s: String) -> Self {
94 Error::UnknownError(s)
95 }
96}
97
98impl Display for Error {
99 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
100 match self {
101 Self::ServiceDoesNotExist(ref s) => write!(f, "Service `{}` does not exist", s),
102 Self::ServiceNotInstantiated(ref s) => write!(f, "Service `{}` is not instantiated", s),
103 Self::FailedToDowncastRefOfService(ref s) => {
104 write!(f, "Failed to downcast service {}", s)
105 }
106 Self::FailedToStoreService(ref s) => write!(f, "Service `{}` Could not be stored", s),
107 Self::NoFactoryFunctionAvailable(ref s) => {
108 write!(f, "Service `{}` Does not contain a Factory function", s)
109 }
110 Self::SetFailedToReturnAServiceReference(ref s) => write!(
111 f,
112 "Storing the service `{}` failed to return a reference of the service",
113 s
114 ),
115 Self::FailedToDowncastFactoryOutput(ref s) => {
116 write!(f, "Failed to downcast Factory output for service {}", s)
117 }
118
119 Self::NoServiceWithStorageRequest => write!(f, "No service with storage request"),
120 Self::FailedToStoreServiceAlias => write!(f, "Service Could not be stored"),
121 Self::MutexGotPoison => write!(f, "Mutex poison"),
122 Self::ServiceAlreadyExists => write!(f, "Service already exists"),
123 Self::FailedToStoreFactory => write!(f, "Failed to store factory"),
124 Self::UnknownError(s) => write!(f, "An unknown error happened: {}", s),
125 }
126 }
127}
128
129/// setting up the support for std::error::Error to allow error handling and passthroughs
130/// ```
131/// pub enum SomeError {
132/// CustomError(Box<dyn std::error::Error + Send>)
133/// }
134/// ```
135/// The concept of this is that it will allow for either alter parsing of the Error value later
136/// without the loss of information.
137impl std::error::Error for Error {}
138
139/// Singleton Manager
140/// The container of the singleton managers information.
141/// This allows to set aliases to lookup the stored singleton, and allowing for creating a factory
142/// function to be set. In the case that the Singleton is never used the factory will stay dormant.
143///
144pub struct SingletonManager {
145 /// The singleton for the "service" or structure that needs a singular instantiation.
146 singletons: HashMap<Uuid, Box<dyn Any>>,
147 /// A factory function that can be used for creating the singleton
148 singleton_factories: HashMap<Uuid, Box<dyn Fn() -> Box<dyn Any>>>,
149 // instance_type: HashMap<Uuid, String>,
150 /// Alias for the actual Singleton. This is linking an actual name to the singleton storage.
151 alias: HashMap<String, Uuid>,
152}
153
154impl SingletonManager {
155 fn new() -> SingletonManager {
156 SingletonManager {
157 singletons: HashMap::new(),
158 singleton_factories: HashMap::new(),
159 // instance_type: HashMap::new(),
160 alias: HashMap::new(),
161 }
162 }
163
164 /// Getting the instance of the SigneltonManager
165 /// This will return a static reference to the singleton manager.
166 /// ```
167 /// use singleton_manager::SingletonManager;
168 ///
169 /// let sm = SingletonManager::instance();
170 /// ```
171 /// A simple way to get the singleton manager
172 pub fn instance() -> &'static mut SingletonManager {
173 unsafe {
174 ONCE.call_once(|| INSTANCE = Cell::new(Some(SingletonManager::new())));
175 match *INSTANCE.as_ptr() {
176 Some(ref mut messenger) => messenger,
177 None => panic!("Failed to get instance"),
178 }
179 }
180 }
181
182 /// Implementation of provider sets
183 ///
184 /// > NOTE:
185 /// > This is currently being implemented and the expectation is that the singleton manager
186 /// > will be moving more and more towards using the provider implementation in the future.
187 ///
188 /// This allows you to implement a `SingletonProvider` trait for a `struct` and form there just
189 /// service the implemented struct to the Singleton Manager.
190 /// The Singleton Manager can then on a need to need basis either get the singleton from its own
191 /// storage or create the service in its own storage before serving it. Giving the
192 /// Singleton Manager total access over when a service should be created and reused.
193 ///
194 /// Usage:
195 /// ```
196 /// use singleton_manager::{SingletonManager, SingletonProvider};
197 /// use std::sync::Mutex;
198 ///
199 /// struct MyService{
200 /// message: String,
201 /// guard: Mutex<()>
202 /// };
203 ///
204 /// impl MyService {
205 /// pub fn set(&mut self, msg: &str) {
206 /// let mut _guard = self.guard.lock().expect("Failed to get guard");
207 /// self.message = msg.to_string();
208 /// }
209 ///
210 /// pub fn get(&self) -> String {
211 /// let _guard = self.guard.lock();
212 /// self.message.clone()
213 /// }
214 /// }
215 ///
216 /// impl SingletonProvider for MyService {
217 /// type Output = MyService;
218 /// type Error = String;
219 ///
220 /// fn service() -> Result<&'static mut Self::Output, Self::Error> {
221 /// SingletonManager::instance().get::<Self::Output>("my_service").map_err(|_| "err".to_string())
222 /// }
223 ///
224 /// fn get_name(&self) -> &'static str {
225 /// "my_service"
226 /// }
227 ///
228 /// fn get_service(&self) -> Result<Self::Output, Self::Error> {
229 /// Ok(MyService{
230 /// message: "".to_string(),
231 /// guard: Mutex::new(()),
232 /// })
233 /// }
234 /// }
235 ///
236 /// SingletonManager::instance().provide(MyService {
237 /// message: "".to_string(),
238 /// guard: Mutex::new(()),
239 /// });
240 /// ```
241 pub fn provide(&'static mut self, sp: impl SingletonProvider) -> Result<()> {
242 let t = sp.get_service().map_err(|e| e.into())?;
243 self.set(sp.get_name(), t).map(|_| ())
244 }
245
246 /// get with default,
247 ///
248 /// This will get a singleton from the singleton manager.
249 /// If the singleton does not exist it will automatically create it from the default factory
250 /// function and then store the build singleton.
251 ///
252 pub fn get_default<T: 'static, F: 'static>(
253 &self,
254 service_name: &str,
255 factory: F,
256 ) -> Result<&'static mut T>
257 where
258 F: Fn() -> Box<dyn Any>,
259 {
260 if !self.has(service_name) {
261 SingletonManager::instance()
262 .set_factory(service_name, factory)
263 .ok();
264 }
265 sm().get::<T>(service_name)
266 }
267
268 pub fn has(&self, service_name: &str) -> bool {
269 self.alias.contains_key(service_name)
270 }
271
272 /// Getting a singleton from the singleton manager.
273 /// This allow you to get a certain singleton from the singleton manager.
274 /// This will automatically try to downcast the singleton to the expected object, if the
275 /// downcast failes it will return an Error `FailedToDowncastRefOfService([Service_name])`
276 /// to let you know that the downcast failed for the sytsem.
277 ///
278 /// To use this just use the following code:
279 ///
280 /// ```
281 /// use singleton_manager::SingletonManager;
282 /// use singleton_manager::sm;
283 ///
284 /// struct MyService{};
285 ///
286 /// sm().set("my_service", MyService {}).unwrap();
287 ///
288 /// let service = sm().get::<MyService>("my_service")
289 /// .expect("Failed to get service");
290 /// ```
291 ///
292 /// this will give you the `my_service` that have been set previously.
293 /// A full example of its usage can be found here:
294 pub fn get<T: 'static>(&'static mut self, service_name: &str) -> Result<&'static mut T> {
295 SingletonManager::instance()
296 .alias
297 .get(service_name)
298 .ok_or_else(|| Error::ServiceDoesNotExist(service_name.to_string()))
299 .and_then(|id| sm().singleton_get(id))
300 .and_then(|service_box| {
301 service_box
302 .downcast_mut::<T>()
303 .ok_or_else(|| Error::FailedToDowncastRefOfService(service_name.to_string()))
304 })
305 }
306
307 /// Setting a specific service/object as a singleton.
308 /// This is used when setting a service or other to a singleton.
309 pub fn set<T: 'static>(&self, service_name: &str, service: T) -> Result<&'static mut T> {
310 sm().store_alias(service_name).and_then(|id| {
311 sm().singleton_set(id, Box::new(service))
312 .and_then(|service_box| {
313 service_box.downcast_mut::<T>().ok_or_else(|| {
314 Error::FailedToDowncastRefOfService(service_name.to_string())
315 })
316 })
317 })
318 }
319
320 pub fn set_factory<F: 'static + Fn() -> Box<dyn Any>>(
321 &self,
322 service_name: &str,
323 factory: F,
324 ) -> Result<&'static mut Box<dyn Fn() -> Box<dyn Any>>> {
325 sm().store_alias(service_name)
326 .and_then(|id| sm().singleton_factory_set(&id, Box::new(factory)))
327 }
328
329 fn store_alias(&self, alias: &str) -> Result<Uuid> {
330 if sm().alias.contains_key(alias) {
331 Err(Error::ServiceAlreadyExists)
332 } else {
333 sm().alias.insert(alias.to_string(), Uuid::new_v4());
334 if let Some(id) = sm().alias.get(alias) {
335 Ok(*id)
336 } else {
337 Err(Error::FailedToStoreServiceAlias)
338 }
339 }
340 }
341
342 fn singleton_get(&'static mut self, alias: &Uuid) -> Result<&mut Box<dyn Any>> {
343 sm().singletons
344 .get_mut(alias)
345 .ok_or_else(|| Error::ServiceDoesNotExist(alias.to_string()))
346 .or_else(|_| {
347 if sm().singleton_factories.contains_key(alias) {
348 sm().factory(alias)
349 } else {
350 Err(Error::ServiceDoesNotExist(alias.to_string()))
351 }
352 })
353 }
354
355 fn singleton_set(&self, id: Uuid, service: Box<dyn Any>) -> Result<&'static mut Box<dyn Any>> {
356 sm().singletons.insert(id, service);
357 if sm().singletons.contains_key(&id) {
358 sm().singletons
359 .get_mut(&id)
360 .ok_or_else(|| Error::FailedToStoreService(id.to_string()))
361 } else {
362 Err(Error::ServiceAlreadyExists)
363 }
364 }
365
366 fn singleton_factory_set<F: 'static + Fn() -> Box<dyn Any>>(
367 &self,
368 id: &Uuid,
369 factory: Box<F>,
370 ) -> Result<&'static mut Box<dyn Fn() -> Box<dyn Any>>> {
371 sm().singleton_factories.insert(*id, factory);
372 if self.singleton_factories.contains_key(&id) {
373 sm().singleton_factories
374 .get_mut(&id)
375 .ok_or(Error::FailedToStoreFactory)
376 } else {
377 Err(Error::FailedToStoreFactory)
378 }
379 }
380
381 fn factory(&'static mut self, alias: &Uuid) -> Result<&mut Box<dyn Any>> {
382 if let Some(box_func) = self.singleton_factories.get_mut(alias) {
383 sm().execute_factory(box_func)
384 .map(|service| self.singletons.insert(*alias, service))
385 .ok();
386 if self.singletons.contains_key(alias) {
387 sm().singletons
388 .get_mut(alias)
389 .ok_or_else(|| Error::ServiceDoesNotExist(alias.to_string()))
390 } else {
391 Err(Error::ServiceDoesNotExist(alias.to_string()))
392 }
393 } else {
394 Err(Error::NoFactoryFunctionAvailable(alias.to_string()))
395 }
396 }
397
398 fn execute_factory(
399 &'static mut self,
400 factory: &mut Box<dyn Fn() -> Box<dyn Any>>,
401 ) -> Result<Box<dyn Any>> {
402 let func = factory.deref_mut();
403 let service = func();
404 Ok(service)
405 }
406
407 // fn get_alias(&'static self, alias: &str) -> Result<&Uuid, Error> {
408 // self.alias
409 // .get(alias)
410 // .ok_or(Error::ServiceDoesNotExist(alias.to_string()))
411 // }
412}
413
414pub trait SingletonProvider {
415 type Output: 'static;
416 type Error: Into<Error>;
417 fn service() -> std::result::Result<&'static mut Self::Output, Self::Error>;
418 fn get_name(&self) -> &'static str;
419 fn get_service(&self) -> std::result::Result<Self::Output, Self::Error>;
420}
421
422pub fn sm() -> &'static mut SingletonManager {
423 SingletonManager::instance()
424}
425pub fn singleton_manager() -> &'static mut SingletonManager {
426 SingletonManager::instance()
427}
428// pub fn set_factory<T: 'static>(&self, service_name: &str, factory: T) -> Result<(), String> {}
429
430#[cfg(test)]
431mod test {
432 use super::SingletonManager;
433
434 use std::ops::Deref;
435 use std::sync::Mutex;
436
437 struct SingletonService1 {
438 something: String,
439 }
440
441 #[derive(Debug)]
442 pub struct MyService {
443 message: String,
444 guard: Mutex<()>,
445 }
446
447 impl MyService {
448 pub fn set(&mut self, msg: &str) {
449 let mut _guard = self.guard.lock().expect("Failed to get guard");
450 self.message = msg.to_string();
451 }
452
453 pub fn get(&self) -> String {
454 let _guard = self.guard.lock();
455 self.message.clone()
456 }
457 }
458
459 #[test]
460 pub fn test_instance() {
461 SingletonManager::instance();
462 }
463
464 #[test]
465 pub fn set_singleton() {
466 SingletonManager::instance()
467 .set(
468 "my_service_0",
469 Box::new(SingletonService1 {
470 something: "hello".to_string(),
471 }),
472 )
473 .unwrap();
474 }
475
476 #[test]
477 pub fn set_get_singleton() {
478 SingletonManager::instance()
479 .set(
480 "my_service_1",
481 SingletonService1 {
482 something: "hello".to_string(),
483 },
484 )
485 .unwrap();
486 let var = SingletonManager::instance()
487 .get::<SingletonService1>("my_service_1")
488 .unwrap()
489 .something
490 .clone();
491
492 assert_eq!("hello".to_string(), var);
493 }
494
495 // #[test]
496 // #[warn(clippy::unnecessary_operation)]
497 // fn test_downcast() {
498 // let instance_name = "MyService";
499 // let service_name = "my_downcast_test";
500 // let my_function = Some(Box::new(|| {
501 // Box::new(MyService {
502 // message: "".to_string(),
503 // guard: Mutex::new(()),
504 // })
505 // }));
506 // my_function
507 // .as_ref()
508 // .ok_or_else(|| super::Error::NoFactoryFunctionAvailable(service_name.to_string()))
509 // .map(|f| (instance_name, f))
510 // .map(|(instance, factory)| {
511 // let func = factory.deref();
512 // let output = func.call(());
513 // (instance, output as Box<MyService>)
514 // })
515 // .map(|(_instance_name, service)| service)
516 // .map(|s| println!("{:?}", s))
517 // .ok();
518 // }
519
520 #[test]
521 fn test_setting_and_getting_from_example() {
522 SingletonManager::instance()
523 .set(
524 "my_service",
525 MyService {
526 message: "".to_string(),
527 guard: Mutex::new(()),
528 },
529 )
530 .ok();
531
532 let service = SingletonManager::instance()
533 .get::<MyService>("my_service")
534 .expect("Failed to get service");
535 service.set("My Message");
536
537 let different_service = SingletonManager::instance()
538 .get::<MyService>("my_service")
539 .expect("Failed to get service");
540 assert_eq!("My Message".to_string(), different_service.get());
541 }
542
543 #[test]
544 fn test_setting_and_getting_from_example_factory() {
545 SingletonManager::instance()
546 .set_factory("my_service_factory", || {
547 Box::new(MyService {
548 message: "".to_string(),
549 guard: Mutex::new(()),
550 })
551 })
552 .ok();
553
554 let service = SingletonManager::instance()
555 .get::<MyService>("my_service_factory")
556 .unwrap();
557 service.set("My Message");
558
559 let different_service = SingletonManager::instance()
560 .get::<MyService>("my_service_factory")
561 .unwrap();
562 assert_eq!("My Message".to_string(), different_service.get());
563 }
564
565 #[test]
566 fn test_setting_and_getting_from_example_default_factory() {
567 let service: &mut MyService = SingletonManager::instance()
568 .get_default("my_default_service_factory", || {
569 Box::new(MyService {
570 message: "".to_string(),
571 guard: Mutex::new(()),
572 })
573 })
574 .unwrap();
575 service.set("My Message");
576
577 assert_eq!("My Message".to_string(), service.get());
578 }
579}