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}