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)]
44mod tests {
45 use super::*;
46 use crate::animation::{Easing, Keyframe};
47
48 #[test]
49 fn animated_value_static_should_return_constant_at_any_time() {
50 let v: AnimatedValue<f64> = AnimatedValue::Static(42.0);
51 assert!(
52 (v.value_at(Duration::ZERO) - 42.0).abs() < f64::EPSILON,
53 "expected 42.0 at t=0"
54 );
55 assert!(
56 (v.value_at(Duration::from_secs(9999)) - 42.0).abs() < f64::EPSILON,
57 "expected 42.0 at t=9999s"
58 );
59 }
60
61 #[test]
62 fn animated_value_track_should_delegate_to_track() {
63 let track = AnimationTrack::new()
64 .push(Keyframe::new(Duration::ZERO, 0.0_f64, Easing::Linear))
65 .push(Keyframe::new(
66 Duration::from_secs(1),
67 1.0_f64,
68 Easing::Linear,
69 ));
70 let v: AnimatedValue<f64> = AnimatedValue::Track(track);
71 let mid = v.value_at(Duration::from_millis(500));
72 assert!(
73 (mid - 0.5).abs() < 1e-9,
74 "expected 0.5 at midpoint, got {mid}"
75 );
76 }
77}