use std::any::{Any, TypeId};
use std::sync::{Arc, Mutex};
use crate::*;
pub trait Builder: Send + Sync {
fn instance_type_id(&self) -> TypeId;
fn instance_type_name(&self) -> &'static str;
fn interfaces(&self) -> Vec<InterfaceDesc>; fn get(&self, cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError>;
fn check(&self, cat: &Catalog) -> Result<(), ValidationError>;
}
pub trait TypedBuilder<T: Send + Sync>: Builder {
fn get(&self, cat: &Catalog) -> Result<Arc<T>, InjectionError>;
}
pub trait Component {
type Builder: Builder;
fn builder() -> Self::Builder;
fn register(cat: &mut CatalogBuilder);
}
#[derive(Debug, Copy, Clone)]
pub struct InterfaceDesc {
pub type_id: TypeId,
pub type_name: &'static str,
}
impl<Impl> Builder for Arc<Impl>
where
Impl: Send + Sync + 'static,
{
fn instance_type_id(&self) -> TypeId {
TypeId::of::<Impl>()
}
fn instance_type_name(&self) -> &'static str {
std::any::type_name::<Impl>()
}
fn interfaces(&self) -> Vec<InterfaceDesc> {
Vec::new()
}
fn get(&self, _cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
Ok(self.clone())
}
fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
Ok(())
}
}
impl<Impl> TypedBuilder<Impl> for Arc<Impl>
where
Impl: Send + Sync + 'static,
{
fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
Ok(self.clone())
}
}
impl<Fct, Impl> Builder for Fct
where
Fct: Fn() -> Arc<Impl> + Send + Sync,
Impl: Send + Sync + 'static,
{
fn instance_type_id(&self) -> TypeId {
TypeId::of::<Impl>()
}
fn instance_type_name(&self) -> &'static str {
std::any::type_name::<Impl>()
}
fn interfaces(&self) -> Vec<InterfaceDesc> {
Vec::new()
}
fn get(&self, _cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
Ok(self())
}
fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
Ok(())
}
}
impl<Fct, Impl> TypedBuilder<Impl> for Fct
where
Fct: Fn() -> Arc<Impl> + Send + Sync,
Impl: Send + Sync + 'static,
{
fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
Ok(self())
}
}
pub(crate) struct Lazy<Fct, Impl>
where
Fct: FnOnce() -> Impl,
Impl: 'static + Send + Sync,
{
state: Mutex<LazyState<Fct, Impl>>,
}
struct LazyState<Fct, Impl> {
factory: Option<Fct>,
instance: Option<Arc<Impl>>,
}
impl<Fct, Impl> Lazy<Fct, Impl>
where
Fct: FnOnce() -> Impl,
Impl: 'static + Send + Sync,
{
pub fn new(factory: Fct) -> Self {
Self {
state: Mutex::new(LazyState {
factory: Some(factory),
instance: None,
}),
}
}
}
impl<Fct, Impl> Builder for Lazy<Fct, Impl>
where
Fct: FnOnce() -> Impl + Send + Sync,
Impl: 'static + Send + Sync,
{
fn instance_type_id(&self) -> TypeId {
TypeId::of::<Impl>()
}
fn instance_type_name(&self) -> &'static str {
std::any::type_name::<Impl>()
}
fn interfaces(&self) -> Vec<InterfaceDesc> {
Vec::new()
}
fn get(&self, cat: &Catalog) -> Result<Arc<dyn Any + Send + Sync>, InjectionError> {
Ok(TypedBuilder::get(self, cat)?)
}
fn check(&self, _cat: &Catalog) -> Result<(), ValidationError> {
Ok(())
}
}
impl<Fct, Impl> TypedBuilder<Impl> for Lazy<Fct, Impl>
where
Fct: FnOnce() -> Impl + Send + Sync,
Impl: 'static + Send + Sync,
{
fn get(&self, _cat: &Catalog) -> Result<Arc<Impl>, InjectionError> {
let mut s = self.state.lock().unwrap();
if let Some(inst) = s.instance.as_ref() {
Ok(inst.clone())
} else {
let factory = s.factory.take().unwrap();
let inst = Arc::new(factory());
s.instance = Some(inst.clone());
Ok(inst)
}
}
}