qecs-core 0.0.13

Soon to be highly flexible Entity-Component-System framework, core lib.
Documentation
use store::StoreBase;
use buffer::BufferBase;
use id_manager::PrimaryIdManager;
use subsystem::SubsystemBase;
use process::ProcessBase;

use ioc::{Ioc, IocBuilder};

use std::fmt::Debug;
use std::sync::RwLock;

pub struct Simulation<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> {
    ids: RwLock<IdMgr>,

    subsystems: Ioc<Key, SsysBase>,
    stores: Ioc<Key, StoBase>,
    buffers: Ioc<Key, BufBase>,

    pipeline: Vec<Ioc<Key, ProcBase>>,

    paused: bool,
}

impl<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> Simulation<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> 
where
    IdMgr: PrimaryIdManager,
    Key: Debug + Ord,
    SsysBase: SubsystemBase,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    ProcBase: ProcessBase<IdMgr, Key, SsysBase, StoBase, BufBase>,
{
    pub fn ids(&self) -> &RwLock<IdMgr> { &self.ids }
    pub fn subsystems(&self) -> &Ioc<Key, SsysBase> { &self.subsystems }
    pub fn stores(&self) -> &Ioc<Key, StoBase> { &self.stores }
    pub fn buffers(&self) -> &Ioc<Key, BufBase> { &self.buffers }

    pub fn update(&mut self){
        if self.is_paused(){ self.unpause(); }

        // trigger `on_before_frame`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_before_frame();
        }

        // clear all event buffers
        for (_, mut buffer) in self.buffers.write_all().unwrap() {
            buffer.clear();
        }

        // run state through the pipeline
        for stage in &self.pipeline {
            for (_, mut process) in stage.write_all().unwrap() {
                process._update(&self.ids, &self.subsystems, &self.stores, &self.buffers);
            }
        }

        // trigger `on_after_frame`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_after_frame();
        }
    }

    pub fn is_paused(&self) -> bool { self.paused }

    pub fn pause(&mut self){
        if self.is_paused() { return; }

        self.paused = true;

        // trigger `on_before_pause`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_before_pause();
        }
    }

    pub fn unpause(&mut self){
        if !self.is_paused() { return; }

        self.paused = false;

        // trigger `on_after_pause`
        for (_, mut subsystem) in self.subsystems.write_all().unwrap() {
            subsystem.on_after_pause();
        }
    }
}

pub struct SimulationBuilder<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> {
    ids: IdMgr,
    
    subsystems: IocBuilder<Key, SsysBase>,
    stores: IocBuilder<Key, StoBase>,
    buffers: IocBuilder<Key, BufBase>,

    pipeline: Vec<IocBuilder<Key, ProcBase>>,
}

impl<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> SimulationBuilder<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> 
where
    IdMgr: PrimaryIdManager,
    Key: Debug + Ord,
    SsysBase: SubsystemBase,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    ProcBase: ProcessBase<IdMgr, Key, SsysBase, StoBase, BufBase>,
{
    pub fn new(ids: IdMgr) -> Self {
        SimulationBuilder{
            ids: ids, 
            subsystems: IocBuilder::new(), 
            stores: IocBuilder::new(),
            buffers: IocBuilder::new(),
            pipeline: Vec::new(),
        }
    }

    pub fn stores(&mut self) -> &mut IocBuilder<Key, StoBase> { &mut self.stores }
    pub fn buffers(&mut self) -> &mut IocBuilder<Key, BufBase> { &mut self.buffers }
    pub fn subsystems(&mut self) -> &mut IocBuilder<Key, SsysBase> { &mut self.subsystems }

    /// TODO: This isn't very user-friendly. Currently works fine if you have a fixed amount
    /// of stages, but beyond that it's quite whacky.
    pub fn pipeline(&mut self) -> &mut Vec<IocBuilder<Key, ProcBase>> { &mut self.pipeline }

    pub fn build(self) -> Simulation<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> {
        Simulation{ 
            ids: RwLock::new(self.ids), 
            subsystems: self.subsystems.build(),
            stores: self.stores.build(),
            buffers: self.buffers.build(),
            pipeline: self.pipeline.into_iter().map(|stage| stage.build()).collect(),
            paused: false,
        }
    }
}

impl<IdMgr, Key, SsysBase: ?Sized, StoBase: ?Sized, BufBase: ?Sized, ProcBase: ?Sized> Default for SimulationBuilder<IdMgr, Key, SsysBase, StoBase, BufBase, ProcBase> 
where
    IdMgr: Default + PrimaryIdManager,
    Key: Debug + Ord,
    SsysBase: SubsystemBase,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    ProcBase: ProcessBase<IdMgr, Key, SsysBase, StoBase, BufBase>,
{
    fn default() -> Self { Self::new(IdMgr::default()) } 
}