use embedded_time::{duration::Seconds, Clock, Instant};
use heapless::Deque;
#[derive(Debug, Clone)]
pub struct FPS<const MAX_FPS: usize, C: Clock> {
last_second_frames: Deque<Instant<C>, MAX_FPS>,
clock: C,
}
impl<const MAX_FPS: usize, C: Clock> FPS<MAX_FPS, C> {
pub fn new(clock: C) -> FPS<MAX_FPS, C> {
FPS {
last_second_frames: Deque::<_, MAX_FPS>::new(),
clock,
}
}
pub fn tick(&mut self) -> usize {
self.try_tick().unwrap()
}
pub fn tick_max(&mut self) -> usize {
self.try_tick_max().unwrap()
}
pub fn try_tick_max(&mut self) -> Result<usize, Error> {
match self.try_tick() {
Ok(fps) => Ok(fps),
Err(Error::MaxFPS(_)) => Ok(MAX_FPS),
Err(err) => Err(err),
}
}
pub fn try_tick(&mut self) -> Result<usize, Error> {
let now = self.clock.try_now().map_err(Error::Clock)?;
let a_second_ago = now - Seconds(1);
while self
.last_second_frames
.front()
.copied()
.map_or(false, |tick| tick < a_second_ago)
{
self.last_second_frames.pop_front();
}
self.last_second_frames
.push_back(now)
.map_err(|_cap_err| Error::MaxFPS(MAX_FPS))?;
Ok(self.last_second_frames.len())
}
}
impl<const MAX_FPS: usize, C> Default for FPS<MAX_FPS, C>
where
C: Clock + Default,
{
fn default() -> Self {
Self::new(C::default())
}
}
#[derive(Debug)]
pub enum Error {
Clock(embedded_time::clock::Error),
MaxFPS(usize),
}