rrt/crates/rrt-runtime/src/calendar.rs

115 lines
2.9 KiB
Rust

use serde::{Deserialize, Serialize};
pub const MONTH_SLOTS_PER_YEAR: u32 = 12;
pub const PHASE_SLOTS_PER_MONTH: u32 = 28;
pub const TICKS_PER_PHASE: u32 = 180;
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct CalendarPoint {
pub year: u32,
pub month_slot: u32,
pub phase_slot: u32,
pub tick_slot: u32,
}
impl CalendarPoint {
pub fn validate(&self) -> Result<(), String> {
if self.month_slot >= MONTH_SLOTS_PER_YEAR {
return Err(format!(
"month_slot {} is out of range 0..{}",
self.month_slot,
MONTH_SLOTS_PER_YEAR - 1
));
}
if self.phase_slot >= PHASE_SLOTS_PER_MONTH {
return Err(format!(
"phase_slot {} is out of range 0..{}",
self.phase_slot,
PHASE_SLOTS_PER_MONTH - 1
));
}
if self.tick_slot >= TICKS_PER_PHASE {
return Err(format!(
"tick_slot {} is out of range 0..{}",
self.tick_slot,
TICKS_PER_PHASE - 1
));
}
Ok(())
}
pub fn step_forward(&mut self) -> BoundaryEventKind {
self.tick_slot += 1;
if self.tick_slot < TICKS_PER_PHASE {
return BoundaryEventKind::Tick;
}
self.tick_slot = 0;
self.phase_slot += 1;
if self.phase_slot < PHASE_SLOTS_PER_MONTH {
return BoundaryEventKind::PhaseRollover;
}
self.phase_slot = 0;
self.month_slot += 1;
if self.month_slot < MONTH_SLOTS_PER_YEAR {
return BoundaryEventKind::MonthRollover;
}
self.month_slot = 0;
self.year += 1;
BoundaryEventKind::YearRollover
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BoundaryEventKind {
Tick,
PhaseRollover,
MonthRollover,
YearRollover,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validates_calendar_bounds() {
let point = CalendarPoint {
year: 1830,
month_slot: 0,
phase_slot: 0,
tick_slot: 0,
};
assert!(point.validate().is_ok());
let invalid = CalendarPoint {
month_slot: MONTH_SLOTS_PER_YEAR,
..point
};
assert!(invalid.validate().is_err());
}
#[test]
fn steps_across_year_boundary() {
let mut point = CalendarPoint {
year: 1830,
month_slot: MONTH_SLOTS_PER_YEAR - 1,
phase_slot: PHASE_SLOTS_PER_MONTH - 1,
tick_slot: TICKS_PER_PHASE - 1,
};
let event = point.step_forward();
assert_eq!(event, BoundaryEventKind::YearRollover);
assert_eq!(
point,
CalendarPoint {
year: 1831,
month_slot: 0,
phase_slot: 0,
tick_slot: 0,
}
);
}
}