use std::fmt; pub trait Task { fn tick(&mut self) {} fn start(&mut self) {} fn stop(&mut self) {} fn name(&self) -> &'static str { core::any::type_name::() } } trait ScheduledState: std::fmt::Debug { fn start(self: Box) -> Box; fn stop(self: Box) -> Box; fn tick(self: Box, task: &mut dyn Task) -> Box; } #[derive(Debug)] struct Starting {} impl ScheduledState for Starting { fn start(self: Box) -> Box { self } fn stop(self: Box) -> Box { Box::new(Stopped {}) } fn tick(self: Box, task: &mut dyn Task) -> Box { task.start(); Box::new(Running{}) } } #[derive(Debug)] struct Running {} impl ScheduledState for Running { fn start(self: Box) -> Box { self } fn stop(self: Box) -> Box { Box::new(Stopping {}) } fn tick(self: Box, task: &mut dyn Task) -> Box { task.tick(); self } } #[derive(Debug)] struct Stopping {} impl ScheduledState for Stopping { fn start(self: Box) -> Box { Box::new(Running {}) } fn stop(self: Box) -> Box { self } fn tick(self: Box, task: &mut dyn Task) -> Box { task.stop(); Box::new(Stopped {}) } } #[derive(Debug)] struct Stopped {} impl ScheduledState for Stopped { fn start(self: Box) -> Box { Box::new(Starting {}) } fn stop(self: Box) -> Box { self } fn tick(self: Box, _task: &mut dyn Task) -> Box { self } } struct ScheduledTask { state: Option>, task: Box, } impl std::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: Some(Box::new(Starting{})), task: task, } } fn start(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.start()); } } fn stop(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.stop()); } } fn tick(&mut self) { if let Some(s) = self.state.take() { self.state = Some(s.tick(self.task.as_mut())); } } } pub struct Scheduler { tasks: Vec, } impl Scheduler { pub fn new(tasks: Vec>) -> Self { let mut scheduled = Vec::new(); for task in tasks { log::info!("Scheduling task {:?}", task.name()); scheduled.push(ScheduledTask::new(task)); } Scheduler { tasks: scheduled } } pub fn tick(&mut self) { for task in &mut self.tasks { task.tick(); } } }