dns_common 0.2.1

Personal toolbelt for Rust code
Documentation
use crate::prelude::*;
use std::collections::hash_map::Entry;

#[derive(Clone)]
pub struct System<C> {
    pub config: Arc<C>,
    components: HashMap<TypeId, Arc<dyn Component>>,
    type_ids: Option<HashSet<TypeId>>,
}

impl<C> System<C> {
    pub fn new(config: C) -> Result<Self> {
        Ok(System {
            config: Arc::new(config),
            components: HashMap::new(),
            type_ids: None,
        })
    }

    pub fn get<T>(&self) -> Result<&T>
    where
        T: Component,
    {
        let type_id = TypeId::of::<T>();
        let c = self.components.get(&type_id).unwrap();
        c.as_any().downcast_ref::<T>().context("invalid component")
    }

    pub fn set_type_ids(&mut self, type_ids: HashSet<TypeId>) {
        self.type_ids = Some(type_ids);
    }

    pub fn maybe_add<T: Component, F: FnOnce(&Self) -> Result<T>>(
        &mut self,
        type_id: &TypeId,
        f: F,
    ) -> Result<Option<Arc<T>>> {
        let should_init = self
            .type_ids
            .as_ref()
            .context("system has no typeIds")?
            .contains(type_id);

        if !should_init {
            Ok(None)
        } else {
            let component = f(self)?;
            let arc = Arc::new(component);
            let entry = self.components.entry(*type_id);
            if let Entry::Vacant(e) = entry {
                e.insert(arc.clone());
                Ok(Some(arc))
            } else {
                Err(anyhow!("typeId already included in component map"))
            }
        }
    }
}