dill 0.15.0

Runtime depenency injection library.
Documentation
use std::any::TypeId;
use std::collections::HashMap;
use std::sync::Arc;

use multimap::MultiMap;

use crate::*;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub(crate) struct IfaceTypeId(pub TypeId);

#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub(crate) struct ImplTypeId(pub TypeId);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[derive(Clone)]
pub(crate) struct CatalogImpl {
    pub(crate) builders: HashMap<ImplTypeId, Arc<dyn Builder>>,
    pub(crate) bindings: MultiMap<IfaceTypeId, Binding>,
    pub(crate) chained_catalog: Option<Arc<CatalogImpl>>,
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

impl CatalogImpl {
    pub fn new(
        builders: HashMap<ImplTypeId, Arc<dyn Builder>>,
        bindings: MultiMap<IfaceTypeId, Binding>,
        chained_catalog: Option<Arc<CatalogImpl>>,
    ) -> Self {
        Self {
            builders,
            bindings,
            chained_catalog,
        }
    }

    pub fn builders<'a>(&'a self) -> Box<dyn Iterator<Item = &'a dyn Builder> + 'a> {
        let it_builders = self.builders.values().map(|b| b.as_ref());
        if let Some(chained_catalog) = &self.chained_catalog {
            Box::new(it_builders.chain(chained_catalog.builders()))
        } else {
            Box::new(it_builders)
        }
    }

    pub fn builders_for<'a, Iface>(
        &'a self,
    ) -> Box<dyn Iterator<Item = TypecastBuilder<'a, Iface>> + 'a>
    where
        Iface: 'static + ?Sized,
    {
        let iface_type = IfaceTypeId(TypeId::of::<Iface>());
        let bindings = self.bindings.get_vec(&iface_type);
        let it_bindings = TypecastBuilderIterator::new(bindings);

        if let Some(chained_catalog) = &self.chained_catalog {
            Box::new(it_bindings.chain(chained_catalog.builders_for::<Iface>()))
        } else {
            Box::new(it_bindings)
        }
    }

    pub fn builders_for_with_meta<'a, Iface, Meta>(
        &'a self,
        pred: impl Fn(&Meta) -> bool + Copy + 'a,
    ) -> Box<dyn Iterator<Item = TypecastBuilder<'a, Iface>> + 'a>
    where
        Iface: 'static + ?Sized,
        Meta: 'static,
    {
        let iface_type = IfaceTypeId(TypeId::of::<Iface>());
        let bindings = self.bindings.get_vec(&iface_type);

        let it_bindings =
            TypecastPredicateBuilderIterator::new(bindings, move |b| b.metadata_contains(pred));

        if let Some(chained_catalog) = &self.chained_catalog {
            Box::new(it_bindings.chain(chained_catalog.builders_for_with_meta::<Iface, Meta>(pred)))
        } else {
            Box::new(it_bindings)
        }
    }
}