use crate::*;
use std::any::Any;
use std::any::TypeId;
use std::collections::HashMap;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use std::sync::Mutex;
type ASS = dyn Any + Send + Sync;
#[derive(Debug)]
pub struct FacRef<T: Sized> {
value: Arc<ASS>,
_data: PhantomData<T>,
}
impl<T: 'static> Deref for FacRef<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
(*self.value).downcast_ref().expect(NOT_POSSIBLE)
}
}
#[derive(PartialEq, Eq, Debug, Copy, Clone)]
pub enum FactoryScope {
Singleton,
AlwaysNewCreated,
}
pub trait Factory: Sized {
type Env: Environment;
fn env(&self) -> &Self::Env;
fn get_or_build<T: FromFactory>(&self) -> Result<FacRef<T>, PropertyError>;
fn init<T: FromFactory>(&self) -> Result<(), PropertyError> {
let _ = self.get_or_build::<T>()?;
Ok(())
}
}
pub(crate) struct FactoryRegistry<T: Environment> {
pub(crate) env: T,
repository: Mutex<HashMap<TypeId, Arc<ASS>>>,
}
impl<E: Environment> FactoryRegistry<E> {
pub(crate) fn new(env: E) -> Self {
Self {
env,
repository: Mutex::new(HashMap::new()),
}
}
}
impl<E: Environment> Factory for FactoryRegistry<E> {
type Env = E;
fn env(&self) -> &Self::Env {
&self.env
}
fn get_or_build<T: 'static + FromFactory>(&self) -> Result<FacRef<T>, PropertyError> {
if T::scope() == FactoryScope::AlwaysNewCreated {
return Ok(FacRef {
value: Arc::new(T::build(self)),
_data: PhantomData,
});
}
let tid = TypeId::of::<T>();
if let Some(value) = self.repository.lock().expect(NOT_POSSIBLE).get(&tid) {
return Ok(FacRef {
value: value.clone(),
_data: PhantomData,
});
}
let value = Arc::new(T::build(self)?);
self.repository
.lock()
.expect(NOT_POSSIBLE)
.entry(tid)
.or_insert(value.clone());
Ok(FacRef {
value,
_data: PhantomData,
})
}
}
pub trait FromFactory: Sync + Send + Sized + Any {
fn build(fac: &impl Factory) -> Result<Self, PropertyError>;
fn scope() -> FactoryScope {
FactoryScope::Singleton
}
}
impl<E: Environment> Environment for FactoryRegistry<E> {
fn require<T: FromEnvironment>(&self, name: &str) -> Result<T, PropertyError> {
self.env.require(name)
}
fn resolve_placeholder(&self, value: String) -> Result<Option<Property>, PropertyError> {
self.env.resolve_placeholder(value)
}
fn find_keys(&self, prefix: &str) -> Vec<String> {
self.env.find_keys(prefix)
}
fn reload(&mut self) -> Result<(), PropertyError> {
self.env.reload()
}
}
#[cfg(feature = "enable_derive")]
impl<F: 'static + Sync + Send + DefaultSourceFromEnvironment> FromFactory for F {
fn build(fac: &impl Factory) -> Result<Self, PropertyError> {
fac.env().load_config()
}
}
#[cfg(test)]
mod tests {
use crate::*;
use rand::random;
#[derive(Eq, PartialEq)]
struct Connection {
value: u64,
}
impl Connection {
fn value(&self) -> u64 {
self.value
}
}
impl FromFactory for Connection {
fn build(_: &impl Factory) -> Result<Self, PropertyError> {
Ok(Connection { value: random() })
}
}
struct Repository {
conn: FacRef<Connection>,
}
impl FromFactory for Repository {
fn build(fac: &impl Factory) -> Result<Self, PropertyError> {
Ok(Repository {
conn: fac.get_or_build()?,
})
}
}
impl Repository {
fn value(&self) -> u64 {
(*self.conn).value()
}
}
#[test]
fn cache_test() {
let fr = FactoryRegistry::new(SourceRegistry::new());
let a = fr.get_or_build::<Connection>().unwrap();
let b = fr.get_or_build::<Connection>().unwrap();
let c = Connection::build(&fr).unwrap();
assert_eq!(a.value(), b.value());
assert_ne!(c.value, b.value());
let r = fr.get_or_build::<Repository>().unwrap();
assert_eq!(a.value(), r.value());
}
}