ff_filter/animation/
value.rs1use std::time::Duration;
2
3use super::{AnimationTrack, Lerp};
4
5#[derive(Debug, Clone)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16#[cfg_attr(
17 feature = "serde",
18 serde(bound(
19 serialize = "T: serde::Serialize",
20 deserialize = "T: serde::Deserialize<'de>",
21 ))
22)]
23pub enum AnimatedValue<T: Lerp> {
24 Static(T),
26 Track(AnimationTrack<T>),
28}
29
30impl<T: Lerp> AnimatedValue<T> {
31 pub fn value_at(&self, t: Duration) -> T {
36 match self {
37 AnimatedValue::Static(v) => v.clone(),
38 AnimatedValue::Track(track) => track.value_at(t),
39 }
40 }
41}
42
43#[cfg(test)]
46mod tests {
47 use super::*;
48 use crate::animation::{Easing, Keyframe};
49
50 #[test]
51 fn animated_value_static_should_return_constant_at_any_time() {
52 let v: AnimatedValue<f64> = AnimatedValue::Static(42.0);
53 assert!(
54 (v.value_at(Duration::ZERO) - 42.0).abs() < f64::EPSILON,
55 "expected 42.0 at t=0"
56 );
57 assert!(
58 (v.value_at(Duration::from_secs(9999)) - 42.0).abs() < f64::EPSILON,
59 "expected 42.0 at t=9999s"
60 );
61 }
62
63 #[test]
64 fn animated_value_track_should_delegate_to_track() {
65 let track = AnimationTrack::new()
66 .push(Keyframe::new(Duration::ZERO, 0.0_f64, Easing::Linear))
67 .push(Keyframe::new(
68 Duration::from_secs(1),
69 1.0_f64,
70 Easing::Linear,
71 ));
72 let v: AnimatedValue<f64> = AnimatedValue::Track(track);
73 let mid = v.value_at(Duration::from_millis(500));
74 assert!(
75 (mid - 0.5).abs() < 1e-9,
76 "expected 0.5 at midpoint, got {mid}"
77 );
78 }
79}