98 lines
3.1 KiB
Rust
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)));
|
|
}
|
|
}
|