#![no_std]
#[derive(Clone, Copy, Debug)]
pub struct Carousel {
pub page_count: u8,
pub page_duration_ms: u64,
pub cycle_window_ms: u64,
pub cycle_period_ms: u64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Frame {
Idle,
Page(u8),
}
#[derive(Clone, Copy, Debug)]
pub struct CarouselState {
start: u64,
until: u64,
next_auto: u64,
}
impl CarouselState {
#[must_use]
pub const fn new(first_auto_at_ms: u64) -> Self {
Self {
start: 0,
until: 0,
next_auto: first_auto_at_ms,
}
}
}
impl Carousel {
pub fn frame_at(&self, state: &mut CarouselState, now_ms: u64, triggered: bool) -> Frame {
let auto_due = self.cycle_period_ms != 0 && now_ms >= state.next_auto;
if auto_due {
state.next_auto = now_ms + self.cycle_period_ms;
}
if triggered || auto_due {
state.start = now_ms;
state.until = now_ms + self.cycle_window_ms;
}
if self.page_count == 0 || now_ms >= state.until {
return Frame::Idle;
}
let elapsed = now_ms - state.start;
let step = elapsed / self.page_duration_ms.max(1);
let index = step % u64::from(self.page_count);
Frame::Page(u8::try_from(index).unwrap_or(0))
}
}
#[cfg(test)]
#[path = "tests/carousel.rs"]
mod tests;