vert/modules/
scheduler.rs

1use crate::{
2    app::function_handle::VoidFunctionHandle,
3    utils::{Timing, TimingQueue},
4    Handle, Module,
5};
6
7pub struct Scheduler {
8    on_exit: TimingQueue<VoidFunctionHandle>,
9    on_update: TimingQueue<VoidFunctionHandle>,
10    /// if Some(reason) then at the end of the frame exit the game loop.
11    exit_requested: Option<String>,
12}
13
14impl Module for Scheduler {
15    type Config = ();
16    type Dependencies = ();
17    fn new(_config: Self::Config, _deps: Self::Dependencies) -> anyhow::Result<Self> {
18        Ok(Self {
19            on_exit: TimingQueue::new(),
20            on_update: TimingQueue::new(),
21            exit_requested: None,
22        })
23    }
24}
25
26impl Scheduler {
27    /// # Warning!
28    ///
29    /// Call this function only once each frame in the main module's game loop. Nowhere else!
30    /// Currently hard to protect, while keeping it exposed.
31    pub fn update(&mut self) -> UpdateFlow {
32        for e in self.on_update.iter() {
33            e.call();
34        }
35        if let Some(reason) = self.exit_requested.take() {
36            for e in self.on_exit.iter() {
37                e.call();
38            }
39            return UpdateFlow::Exit(reason);
40        }
41        UpdateFlow::Continue
42    }
43
44    pub fn register_update<M: Module>(
45        &mut self,
46        handle: Handle<M>,
47        timing: Timing,
48        func: fn(&mut M) -> (),
49    ) {
50        self.register(handle, Schedule::Update, timing, func)
51    }
52
53    /// high timing functions will run after low timing ones.
54    pub fn register<M: Module>(
55        &mut self,
56        handle: Handle<M>,
57        schedule: Schedule,
58        timing: Timing,
59        func: fn(&mut M) -> (),
60    ) {
61        // is this okay??
62        let _type_punned_function: fn(*mut ()) -> () = unsafe { std::mem::transmute(func) };
63        let void_function_handle = VoidFunctionHandle::new(handle, func);
64        let schedule = self.schedule(schedule);
65        schedule.insert(void_function_handle, timing); // todo! return a key that contains the schedule, to allow for deregistering.
66    }
67    pub fn request_exit(&mut self, reason: impl ToString) {
68        self.exit_requested = Some(reason.to_string());
69    }
70
71    fn schedule(&mut self, schedule: Schedule) -> &mut TimingQueue<VoidFunctionHandle> {
72        match schedule {
73            Schedule::Exit => &mut self.on_exit,
74            Schedule::Update => &mut self.on_update,
75        }
76    }
77
78    // todo!()  pub fn deregister()
79}
80
81pub enum UpdateFlow {
82    Exit(String),
83    Continue,
84}
85
86#[derive(Debug, Clone, Copy)]
87pub enum Schedule {
88    Exit,
89    Update,
90}