icmd 0.1.0

A command-line software framework
Documentation
use std::{
    any::TypeId,
    sync::Arc,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Mutex, RwLock};

use super::{
    interactor::Interactor,
    message::{Content, Message, Participant, Sender},
    renderer::Renderer,
    ICmdWindow,
};

#[derive(Debug)]
pub struct Looper {
    pub window: Arc<RwLock<ICmdWindow>>,
    pub fps: u16,

    renderer_ready: Mutex<bool>,
    interactor_ready: Mutex<bool>,
}

impl Looper {
    pub fn new(window: Arc<RwLock<ICmdWindow>>, fps: u16) -> Self {
        Looper {
            window,
            fps,
            renderer_ready: false.into(),
            interactor_ready: false.into(),
        }
    }

    pub fn launch(&self) {
        // Check if other threads are ready
        self.send(Message {
            from: self.get_id(),
            to: TypeId::of::<Renderer>(),
            content: Content::IsReady,
        });
        // self.send(Message {
        //     from: self.get_id(),
        //     to: TypeId::of::<Interactor>(),
        //     content: Content::IsReady,
        // });

        let mut last_exec = Instant::now();
        let interval = Duration::from_micros((1000 / self.fps).into());

        loop {
            if !self.update(()) {
                break;
            }

            if *self.renderer_ready.lock() {
                // Run every interval
                if last_exec.elapsed() >= interval {
                    self.send(Message {
                        from: self.get_id(),
                        to: TypeId::of::<Renderer>(),
                        content: Content::Update,
                    });
                    last_exec = Instant::now();
                }
            }

            thread::sleep(Duration::from_millis(1));
        }
    }
}

impl Sender for Looper {
    fn get_window(&self) -> Arc<RwLock<ICmdWindow>> {
        self.window.clone()
    }
}

impl Participant for Looper {
    type Params = ();
    fn resolve(&self, msg: Message, _: Self::Params) -> bool {
        match msg.content {
            Content::Ready => {
                if msg.from == TypeId::of::<Renderer>() {
                    *self.renderer_ready.lock() = true;
                };
                if msg.from == TypeId::of::<Interactor>() {
                    *self.interactor_ready.lock() = true;
                };
                true
            }
            Content::IsReady => {
                self.send(Message {
                    from: self.get_id(),
                    to: msg.from,
                    content: Content::Ready,
                });
                true
            }
            Content::Quit => false,
            _ => true,
        }
    }
}