use core::fmt; use crate::events::{Event, EventBus, Variant}; pub trait Task: Send { fn on_ready(&mut self, bus: &mut EventBus) {} fn on_tick(&mut self, bus: &mut EventBus) {} fn on_property_change(&mut self, key: &'static str, value: &Variant, bus: &mut EventBus) {} fn start(&mut self, bus: &mut EventBus) {} fn stop(&mut self, bus: &mut EventBus) {} fn name(&self) -> &'static str { core::any::type_name::() } } #[derive(Debug, Clone)] enum ScheduledState { Stopped, Start, Running, Stop } struct ScheduledTask { state: ScheduledState, task: Box, } impl core::fmt::Debug for ScheduledTask { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ScheduledTask") .field("task", &self.task.name()) .field("state", &self.state) .finish() } } impl ScheduledTask { fn new(task: Box) -> Self { ScheduledTask { state: ScheduledState::Stopped, task: task, } } fn start(&mut self) { match self.state { ScheduledState::Stopped => self.state = ScheduledState::Start, ScheduledState::Stop => self.state = ScheduledState::Running, _ => () } } fn stop(&mut self) { match self.state { ScheduledState::Running => self.state = ScheduledState::Stop, ScheduledState::Start => self.state = ScheduledState::Stopped, _ => () } } fn tick(&mut self, event: &Event, bus: &mut EventBus) { match self.state { ScheduledState::Start => { log::info!("Starting task {}", self.task.name()); self.task.start(bus); self.state = ScheduledState::Running }, ScheduledState::Stop => { log::info!("Stopping task {}", self.task.name()); self.task.stop(bus); self.state = ScheduledState::Stopped }, _ => () }; match self.state { ScheduledState::Running => { match event { Event::Tick => self.task.on_tick(bus), Event::ReadyToRock => self.task.on_ready(bus), Event::PropertyChange(key, value) => self.task.on_property_change(key, value, bus), _ => () } }, _ => () } } } #[derive(Debug)] pub struct FixedSizeScheduler { tasks: [ScheduledTask; TASK_COUNT], } impl FixedSizeScheduler { pub fn new(tasks: [Box; TASK_COUNT]) -> Self { let mut scheduled: [ScheduledTask; TASK_COUNT] = unsafe { std::mem::MaybeUninit::zeroed().assume_init() }; let mut idx = 0; for task in tasks { log::info!("Scheduling task {}", task.name()); let slot = &mut scheduled[idx]; unsafe { std::ptr::write(slot, ScheduledTask::new(task)) }; idx += 1; } FixedSizeScheduler { tasks: scheduled } } fn find_task(&mut self, name: &str) -> Option<&mut ScheduledTask> { for slot in &mut self.tasks { if slot.task.name() == name { return Some(slot); } } None } } impl Scheduler for FixedSizeScheduler { fn tick(&mut self, event: &Event, bus: &mut EventBus) { match event { Event::StartThing(task_name) => { if let Some(slot) = self.find_task(task_name) { log::debug!("Starting {}", task_name); slot.start(); } }, Event::StopThing(task_name) => { if let Some(slot) = self.find_task(task_name) { log::debug!("Stopping {}", task_name); slot.stop(); } }, _ => { for slot in &mut self.tasks { slot.tick(event, bus); } } } } } pub trait Scheduler { fn tick(&mut self, event: &Event, bus: &mut EventBus); }