ff_filter/animation/
keyframe.rs1use std::cmp::Ordering;
2use std::time::Duration;
3
4use super::{Easing, Lerp};
5
6#[derive(Debug, Clone)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20#[cfg_attr(
21 feature = "serde",
22 serde(bound(
23 serialize = "T: serde::Serialize",
24 deserialize = "T: serde::Deserialize<'de>",
25 ))
26)]
27pub struct Keyframe<T: Lerp> {
28 pub timestamp: Duration,
30 pub value: T,
32 pub easing: Easing,
34}
35
36impl<T: Lerp> Keyframe<T> {
37 pub fn new(timestamp: Duration, value: T, easing: Easing) -> Self {
39 Self {
40 timestamp,
41 value,
42 easing,
43 }
44 }
45}
46
47impl<T: Lerp> PartialEq for Keyframe<T> {
50 fn eq(&self, other: &Self) -> bool {
51 self.timestamp == other.timestamp
52 }
53}
54
55impl<T: Lerp> Eq for Keyframe<T> {}
56
57impl<T: Lerp> PartialOrd for Keyframe<T> {
58 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
59 Some(self.cmp(other))
60 }
61}
62
63impl<T: Lerp> Ord for Keyframe<T> {
64 fn cmp(&self, other: &Self) -> Ordering {
65 self.timestamp.cmp(&other.timestamp)
66 }
67}
68
69#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[derive(Clone, Debug)]
78 struct TestVal(f64);
79
80 impl Lerp for TestVal {
81 fn lerp(a: &Self, b: &Self, t: f64) -> Self {
82 TestVal(a.0 + (b.0 - a.0) * t)
83 }
84 }
85
86 fn kf(ms: u64, v: f64) -> Keyframe<TestVal> {
87 Keyframe::new(Duration::from_millis(ms), TestVal(v), Easing::Linear)
88 }
89
90 #[test]
91 fn keyframe_new_should_store_all_fields() {
92 let ts = Duration::from_millis(500);
93 let kf = Keyframe::new(ts, TestVal(1.0), Easing::EaseInOut);
94 assert_eq!(kf.timestamp, ts);
95 assert!((kf.value.0 - 1.0).abs() < f64::EPSILON);
96 assert!(matches!(kf.easing, Easing::EaseInOut));
97 }
98
99 #[test]
100 fn keyframe_should_order_by_timestamp() {
101 let a = kf(100, 0.0);
102 let b = kf(200, 0.5);
103 let c = kf(300, 1.0);
104
105 assert!(a < b);
106 assert!(b < c);
107 assert!(a < c);
108
109 let mut frames = vec![c, a, b];
110 frames.sort();
111 assert_eq!(frames[0].timestamp, Duration::from_millis(100));
112 assert_eq!(frames[1].timestamp, Duration::from_millis(200));
113 assert_eq!(frames[2].timestamp, Duration::from_millis(300));
114 }
115
116 #[test]
117 fn keyframe_should_compare_equal_by_timestamp_only() {
118 let a = Keyframe::new(Duration::from_millis(100), TestVal(0.0), Easing::Linear);
119 let b = Keyframe::new(Duration::from_millis(100), TestVal(99.0), Easing::Hold);
120 assert_eq!(a, b);
122 assert_eq!(a.cmp(&b), Ordering::Equal);
123 }
124
125 #[test]
126 fn keyframe_should_be_less_than_later_keyframe() {
127 let early = kf(0, 0.0);
128 let late = kf(1000, 1.0);
129 assert!(early < late);
130 assert!(late > early);
131 }
132}