2026-06-05 09:39:03 +01:00

98 lines
3.1 KiB
Rust

use prometeu_hal::FrameId;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FrameAuthorizationError {
GameFrameAlreadyActive { active_frame_id: FrameId },
}
#[derive(Debug, Clone, Default)]
pub struct FrameScheduler {
next_game_frame_id: FrameId,
active_game_frame_id: Option<FrameId>,
completed_game_frames: u64,
logical_frame_overruns: u64,
}
impl FrameScheduler {
pub fn authorize_game_frame(&mut self) -> Result<FrameId, FrameAuthorizationError> {
if let Some(active_frame_id) = self.active_game_frame_id {
return Err(FrameAuthorizationError::GameFrameAlreadyActive { active_frame_id });
}
let frame_id = self.next_game_frame_id;
self.next_game_frame_id = self.next_game_frame_id.next();
self.active_game_frame_id = Some(frame_id);
Ok(frame_id)
}
pub fn complete_game_frame(&mut self) -> Option<FrameId> {
let completed = self.active_game_frame_id.take();
if completed.is_some() {
self.completed_game_frames = self.completed_game_frames.wrapping_add(1);
}
completed
}
pub fn record_logical_frame_overrun(&mut self) {
self.logical_frame_overruns = self.logical_frame_overruns.wrapping_add(1);
}
pub fn active_game_frame_id(&self) -> Option<FrameId> {
self.active_game_frame_id
}
pub fn completed_game_frames(&self) -> u64 {
self.completed_game_frames
}
pub fn logical_frame_overruns(&self) -> u64 {
self.logical_frame_overruns
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn authorizes_one_game_frame_until_completion() {
let mut scheduler = FrameScheduler::default();
assert_eq!(scheduler.authorize_game_frame(), Ok(FrameId::ZERO));
assert_eq!(
scheduler.authorize_game_frame(),
Err(FrameAuthorizationError::GameFrameAlreadyActive { active_frame_id: FrameId::ZERO })
);
assert_eq!(scheduler.complete_game_frame(), Some(FrameId::ZERO));
assert_eq!(scheduler.authorize_game_frame(), Ok(FrameId::new(1)));
}
#[test]
fn completion_is_sequential_without_catch_up_frames() {
let mut scheduler = FrameScheduler::default();
for expected in 0..3 {
let frame_id = scheduler.authorize_game_frame().expect("frame authorization");
assert_eq!(frame_id, FrameId::new(expected));
assert_eq!(scheduler.complete_game_frame(), Some(FrameId::new(expected)));
}
assert_eq!(scheduler.completed_game_frames(), 3);
}
#[test]
fn records_logical_frame_overrun_without_advancing_frame_id() {
let mut scheduler = FrameScheduler::default();
assert_eq!(scheduler.authorize_game_frame(), Ok(FrameId::ZERO));
scheduler.record_logical_frame_overrun();
scheduler.record_logical_frame_overrun();
assert_eq!(scheduler.logical_frame_overruns(), 2);
assert_eq!(scheduler.active_game_frame_id(), Some(FrameId::ZERO));
assert_eq!(scheduler.complete_game_frame(), Some(FrameId::ZERO));
assert_eq!(scheduler.authorize_game_frame(), Ok(FrameId::new(1)));
}
}