qecs-core 0.0.17

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

use ioc::{Ioc, IocBuilder};

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

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

    stores: Ioc<Key, StoBase>,
    buffers: Ioc<Key, BufBase>,
    services: Ioc<Key, SerBase>,

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

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

    pub fn update(&mut self){
        // trigger `on_before_frame`
        for (_, mut store) in self.stores.write_all().unwrap() {
            store.on_before_frame();
        }
        for (_, mut buffer) in self.buffers.write_all().unwrap() {
            buffer.on_before_frame();
        }
        for (_, mut service) in self.services.write_all().unwrap() {
            service.on_before_frame();
        }
        for (_, mut prok) in self.pipeline.iter().flat_map(|p| p.write_all().unwrap()) {
            prok.on_before_frame();
        }

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

        // trigger `on_after_frame`
        for (_, mut store) in self.stores.write_all().unwrap() {
            store.on_after_frame();
        }
        for (_, mut buffer) in self.buffers.write_all().unwrap() {
            buffer.on_after_frame();
        }
        for (_, mut service) in self.services.write_all().unwrap() {
            service.on_after_frame();
        }
        for (_, mut prok) in self.pipeline.iter().flat_map(|p| p.write_all().unwrap()) {
            prok.on_after_frame();
        }
    }
}

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

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

impl<IdMgr, Key, StoBase: ?Sized, BufBase: ?Sized, SerBase: ?Sized, ProcBase: ?Sized> SimulationBuilder<IdMgr, Key, StoBase, BufBase, SerBase, ProcBase> 
where
    IdMgr: PrimaryIdManager,
    Key: Debug + Ord,
    StoBase: StoreBase<Id = IdMgr::Id>,
    BufBase: BufferBase,
    SerBase: ServiceBase,
    ProcBase: ProcessBase<IdMgr, Key, StoBase, BufBase, SerBase>,
{
    pub fn new(ids: IdMgr) -> Self {
        SimulationBuilder{
            ids: ids, 
            stores: IocBuilder::new(),
            buffers: IocBuilder::new(),
            services: 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 services(&mut self) -> &mut IocBuilder<Key, SerBase> { &mut self.services }

    /// 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, StoBase, BufBase, SerBase, ProcBase> {
        Simulation{ 
            ids: RwLock::new(self.ids), 
            stores: self.stores.build(),
            buffers: self.buffers.build(),
            services: self.services.build(),
            pipeline: self.pipeline.into_iter().map(|stage| stage.build()).collect(),
        }
    }
}

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