Skip to main content

aura_anim_core/timing/
mode.rs

1use crate::timing::utils::clamp_progress;
2
3/// Playback direction applied to repeated iterations.
4#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
5pub enum Direction {
6    /// Play each iteration from start to end.
7    #[default]
8    Normal,
9    /// Play each iteration from end to start.
10    Reverse,
11    /// Alternate forward and reverse iterations.
12    Alternate,
13    /// Alternate reverse and forward iterations.
14    AlternateReverse,
15}
16
17impl Direction {
18    pub(crate) fn sample_progress(self, iteration_index: u32, raw_progress: f64) -> f64 {
19        let progress = clamp_progress(raw_progress);
20
21        if self.is_reversed_iteration(iteration_index) {
22            1.0 - progress
23        } else {
24            progress
25        }
26    }
27
28    pub(crate) fn end_progress(self, iteration_count: u32) -> f64 {
29        let last_iteration = iteration_count.saturating_sub(1);
30
31        self.sample_progress(last_iteration, 1.0)
32    }
33
34    pub(crate) fn is_reversed_iteration(self, iteration_index: u32) -> bool {
35        match self {
36            Self::Normal => false,
37            Self::Reverse => true,
38            Self::Alternate => iteration_index % 2 == 1,
39            Self::AlternateReverse => iteration_index.is_multiple_of(2),
40        }
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::Direction;
47    use float_cmp::assert_approx_eq;
48
49    #[test]
50    fn sample_progress_applies_direction() {
51        assert_approx_eq!(f64, Direction::Normal.sample_progress(0, 0.25), 0.25);
52        assert_approx_eq!(f64, Direction::Reverse.sample_progress(0, 0.25), 0.75);
53        assert_approx_eq!(f64, Direction::Alternate.sample_progress(1, 0.25), 0.75);
54        assert_approx_eq!(
55            f64,
56            Direction::AlternateReverse.sample_progress(0, 0.25),
57            0.75
58        );
59    }
60
61    #[test]
62    fn end_progress_uses_last_iteration_direction() {
63        assert_approx_eq!(f64, Direction::Normal.end_progress(3), 1.0);
64        assert_approx_eq!(f64, Direction::Reverse.end_progress(3), 0.0);
65        assert_approx_eq!(f64, Direction::Alternate.end_progress(2), 0.0);
66        assert_approx_eq!(f64, Direction::AlternateReverse.end_progress(2), 1.0);
67    }
68
69    #[test]
70    fn sample_progress_clamps_raw_progress() {
71        assert_approx_eq!(f64, Direction::Normal.sample_progress(0, -1.0), 0.0);
72        assert_approx_eq!(f64, Direction::Normal.sample_progress(0, 2.0), 1.0);
73        assert_approx_eq!(f64, Direction::Normal.sample_progress(0, f64::NAN), 0.0);
74    }
75}