b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 1 | /// A plan's place in time. Every phase lasts `phase_ns`. |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 2 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 3 | pub struct Timeline { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 4 | pub start_ns: u64, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 5 | pub phase_ns: u64, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 6 | pub phases: usize, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 7 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 8 | |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 9 | #[derive(Clone, Copy, Debug, PartialEq)] |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 10 | pub enum Position { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 11 | NotStarted, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 12 | /// Inside `phase`, with linear time `t` in [0, 1) before easing. |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 13 | Phase { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 14 | phase: usize, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 15 | t: f64, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 16 | }, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 17 | Finished, |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 18 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 19 | |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 20 | impl Timeline { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 21 | pub fn end_ns(&self) -> u64 { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 22 | self.start_ns + self.phase_ns * self.phases as u64 |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 23 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 24 | |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 25 | pub fn locate(&self, now_ns: u64) -> Position { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 26 | if now_ns < self.start_ns { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 27 | return Position::NotStarted; |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 28 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 29 | if self.phase_ns == 0 || now_ns >= self.end_ns() { |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 30 | return Position::Finished; |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 31 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 32 | let elapsed = now_ns - self.start_ns; |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 33 | let phase = (elapsed / self.phase_ns) as usize; |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 34 | let t = (elapsed % self.phase_ns) as f64 / self.phase_ns as f64; |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 35 | Position::Phase { phase, t } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 36 | } |
b563d2da1c80 | atagen | 2026-10-16 08:25 UTC | 37 | } |