extern crate uuid;
use std::any::Any;
use std::cell::Cell;
use std::collections::HashMap;
use std::fmt::{Debug, Display, Formatter};
use std::ops::DerefMut;
use std::sync::Once;
use uuid::Uuid;
static mut INSTANCE: Cell<Option<SingletonManager>> = Cell::new(None);
static mut ONCE: Once = Once::new();
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub enum Error {
ServiceDoesNotExist(String),
ServiceNotInstantiated(String),
FailedToDowncastRefOfService(String),
FailedToStoreService(String),
NoFactoryFunctionAvailable(String),
SetFailedToReturnAServiceReference(String),
FailedToDowncastFactoryOutput(String),
NoServiceWithStorageRequest,
FailedToStoreServiceAlias,
MutexGotPoison,
ServiceAlreadyExists,
FailedToStoreFactory,
UnknownError(String),
}
impl From<String> for Error {
fn from(s: String) -> Self {
Error::UnknownError(s)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::ServiceDoesNotExist(ref s) => write!(f, "Service `{}` does not exist", s),
Self::ServiceNotInstantiated(ref s) => write!(f, "Service `{}` is not instantiated", s),
Self::FailedToDowncastRefOfService(ref s) => {
write!(f, "Failed to downcast service {}", s)
}
Self::FailedToStoreService(ref s) => write!(f, "Service `{}` Could not be stored", s),
Self::NoFactoryFunctionAvailable(ref s) => {
write!(f, "Service `{}` Does not contain a Factory function", s)
}
Self::SetFailedToReturnAServiceReference(ref s) => write!(
f,
"Storing the service `{}` failed to return a reference of the service",
s
),
Self::FailedToDowncastFactoryOutput(ref s) => {
write!(f, "Failed to downcast Factory output for service {}", s)
}
Self::NoServiceWithStorageRequest => write!(f, "No service with storage request"),
Self::FailedToStoreServiceAlias => write!(f, "Service Could not be stored"),
Self::MutexGotPoison => write!(f, "Mutex poison"),
Self::ServiceAlreadyExists => write!(f, "Service already exists"),
Self::FailedToStoreFactory => write!(f, "Failed to store factory"),
Self::UnknownError(s) => write!(f, "An unknown error happened: {}", s),
}
}
}
impl std::error::Error for Error {}
pub struct SingletonManager {
singletons: HashMap<Uuid, Box<dyn Any>>,
singleton_factories: HashMap<Uuid, Box<dyn Fn() -> Box<dyn Any>>>,
alias: HashMap<String, Uuid>,
}
impl SingletonManager {
fn new() -> SingletonManager {
SingletonManager {
singletons: HashMap::new(),
singleton_factories: HashMap::new(),
alias: HashMap::new(),
}
}
pub fn instance() -> &'static mut SingletonManager {
unsafe {
ONCE.call_once(|| INSTANCE = Cell::new(Some(SingletonManager::new())));
match *INSTANCE.as_ptr() {
Some(ref mut messenger) => messenger,
None => panic!("Failed to get instance"),
}
}
}
pub fn provide(&'static mut self, sp: impl SingletonProvider) -> Result<()> {
let t = sp.get_service().map_err(|e| e.into())?;
self.set(sp.get_name(), t).map(|_| ())
}
pub fn get_default<T: 'static, F: 'static>(
&self,
service_name: &str,
factory: F,
) -> Result<&'static mut T>
where
F: Fn() -> Box<dyn Any>,
{
if !self.has(service_name) {
SingletonManager::instance()
.set_factory(service_name, factory)
.ok();
}
sm().get::<T>(service_name)
}
pub fn has(&self, service_name: &str) -> bool {
self.alias.contains_key(service_name)
}
pub fn get<T: 'static>(&'static mut self, service_name: &str) -> Result<&'static mut T> {
SingletonManager::instance()
.alias
.get(service_name)
.ok_or_else(|| Error::ServiceDoesNotExist(service_name.to_string()))
.and_then(|id| sm().singleton_get(id))
.and_then(|service_box| {
service_box
.downcast_mut::<T>()
.ok_or_else(|| Error::FailedToDowncastRefOfService(service_name.to_string()))
})
}
pub fn set<T: 'static>(&self, service_name: &str, service: T) -> Result<&'static mut T> {
sm().store_alias(service_name).and_then(|id| {
sm().singleton_set(id, Box::new(service))
.and_then(|service_box| {
service_box.downcast_mut::<T>().ok_or_else(|| {
Error::FailedToDowncastRefOfService(service_name.to_string())
})
})
})
}
pub fn set_factory<F: 'static + Fn() -> Box<dyn Any>>(
&self,
service_name: &str,
factory: F,
) -> Result<&'static mut Box<dyn Fn() -> Box<dyn Any>>> {
sm().store_alias(service_name)
.and_then(|id| sm().singleton_factory_set(&id, Box::new(factory)))
}
fn store_alias(&self, alias: &str) -> Result<Uuid> {
if sm().alias.contains_key(alias) {
Err(Error::ServiceAlreadyExists)
} else {
sm().alias.insert(alias.to_string(), Uuid::new_v4());
if let Some(id) = sm().alias.get(alias) {
Ok(*id)
} else {
Err(Error::FailedToStoreServiceAlias)
}
}
}
fn singleton_get(&'static mut self, alias: &Uuid) -> Result<&mut Box<dyn Any>> {
sm().singletons
.get_mut(alias)
.ok_or_else(|| Error::ServiceDoesNotExist(alias.to_string()))
.or_else(|_| {
if sm().singleton_factories.contains_key(alias) {
sm().factory(alias)
} else {
Err(Error::ServiceDoesNotExist(alias.to_string()))
}
})
}
fn singleton_set(&self, id: Uuid, service: Box<dyn Any>) -> Result<&'static mut Box<dyn Any>> {
sm().singletons.insert(id, service);
if sm().singletons.contains_key(&id) {
sm().singletons
.get_mut(&id)
.ok_or_else(|| Error::FailedToStoreService(id.to_string()))
} else {
Err(Error::ServiceAlreadyExists)
}
}
fn singleton_factory_set<F: 'static + Fn() -> Box<dyn Any>>(
&self,
id: &Uuid,
factory: Box<F>,
) -> Result<&'static mut Box<dyn Fn() -> Box<dyn Any>>> {
sm().singleton_factories.insert(*id, factory);
if self.singleton_factories.contains_key(&id) {
sm().singleton_factories
.get_mut(&id)
.ok_or(Error::FailedToStoreFactory)
} else {
Err(Error::FailedToStoreFactory)
}
}
fn factory(&'static mut self, alias: &Uuid) -> Result<&mut Box<dyn Any>> {
if let Some(box_func) = self.singleton_factories.get_mut(alias) {
sm().execute_factory(box_func)
.map(|service| self.singletons.insert(*alias, service))
.ok();
if self.singletons.contains_key(alias) {
sm().singletons
.get_mut(alias)
.ok_or_else(|| Error::ServiceDoesNotExist(alias.to_string()))
} else {
Err(Error::ServiceDoesNotExist(alias.to_string()))
}
} else {
Err(Error::NoFactoryFunctionAvailable(alias.to_string()))
}
}
fn execute_factory(
&'static mut self,
factory: &mut Box<dyn Fn() -> Box<dyn Any>>,
) -> Result<Box<dyn Any>> {
let func = factory.deref_mut();
let service = func();
Ok(service)
}
}
pub trait SingletonProvider {
type Output: 'static;
type Error: Into<Error>;
fn service() -> std::result::Result<&'static mut Self::Output, Self::Error>;
fn get_name(&self) -> &'static str;
fn get_service(&self) -> std::result::Result<Self::Output, Self::Error>;
}
pub fn sm() -> &'static mut SingletonManager {
SingletonManager::instance()
}
pub fn singleton_manager() -> &'static mut SingletonManager {
SingletonManager::instance()
}
#[cfg(test)]
mod test {
use super::SingletonManager;
use std::ops::Deref;
use std::sync::Mutex;
struct SingletonService1 {
something: String,
}
#[derive(Debug)]
pub struct MyService {
message: String,
guard: Mutex<()>,
}
impl MyService {
pub fn set(&mut self, msg: &str) {
let mut _guard = self.guard.lock().expect("Failed to get guard");
self.message = msg.to_string();
}
pub fn get(&self) -> String {
let _guard = self.guard.lock();
self.message.clone()
}
}
#[test]
pub fn test_instance() {
SingletonManager::instance();
}
#[test]
pub fn set_singleton() {
SingletonManager::instance()
.set(
"my_service_0",
Box::new(SingletonService1 {
something: "hello".to_string(),
}),
)
.unwrap();
}
#[test]
pub fn set_get_singleton() {
SingletonManager::instance()
.set(
"my_service_1",
SingletonService1 {
something: "hello".to_string(),
},
)
.unwrap();
let var = SingletonManager::instance()
.get::<SingletonService1>("my_service_1")
.unwrap()
.something
.clone();
assert_eq!("hello".to_string(), var);
}
#[test]
fn test_setting_and_getting_from_example() {
SingletonManager::instance()
.set(
"my_service",
MyService {
message: "".to_string(),
guard: Mutex::new(()),
},
)
.ok();
let service = SingletonManager::instance()
.get::<MyService>("my_service")
.expect("Failed to get service");
service.set("My Message");
let different_service = SingletonManager::instance()
.get::<MyService>("my_service")
.expect("Failed to get service");
assert_eq!("My Message".to_string(), different_service.get());
}
#[test]
fn test_setting_and_getting_from_example_factory() {
SingletonManager::instance()
.set_factory("my_service_factory", || {
Box::new(MyService {
message: "".to_string(),
guard: Mutex::new(()),
})
})
.ok();
let service = SingletonManager::instance()
.get::<MyService>("my_service_factory")
.unwrap();
service.set("My Message");
let different_service = SingletonManager::instance()
.get::<MyService>("my_service_factory")
.unwrap();
assert_eq!("My Message".to_string(), different_service.get());
}
#[test]
fn test_setting_and_getting_from_example_default_factory() {
let service: &mut MyService = SingletonManager::instance()
.get_default("my_default_service_factory", || {
Box::new(MyService {
message: "".to_string(),
guard: Mutex::new(()),
})
})
.unwrap();
service.set("My Message");
assert_eq!("My Message".to_string(), service.get());
}
}