1use std::fmt::{Display, Formatter};
2
3use crate::animations::Keyframe;
4use crate::devices::Output;
5use crate::errors::Error;
6use crate::utils::{Range, State};
7
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
41#[derive(Clone, Debug)]
42pub struct Track {
43 device: Box<dyn Output>,
46 keyframes: Vec<Keyframe>,
48
49 #[cfg_attr(feature = "serde", serde(skip))]
52 previous: State,
53 #[cfg_attr(feature = "serde", serde(skip))]
54 current: State,
55}
56
57impl Track {
58 #[allow(private_bounds)]
60 pub fn new<T: Output + 'static>(device: T) -> Self {
61 let history = device.get_state();
62 Self {
63 device: Box::new(device),
64 keyframes: vec![],
65 previous: history.clone(),
66 current: history,
67 }
68 }
69
70 pub fn get_duration(&self) -> u64 {
72 match !self.keyframes.is_empty() {
73 false => 0,
74 true => {
75 let last_keyframe = self
76 .keyframes
77 .iter()
78 .max_by(|x, y| x.get_end().cmp(&(y.get_end())))
79 .unwrap();
80 last_keyframe.get_end()
81 }
82 }
83 }
84
85 pub(crate) fn play_frame<F: Into<Range<u64>>>(&mut self, timeframe: F) -> Result<(), Error> {
87 let timeframe = timeframe.into();
88 let keyframe = self.get_best_keyframe(timeframe);
90
91 match keyframe {
92 None => (),
93 Some(keyframe) => {
94 self.update_history(keyframe.get_target());
95 let progress = keyframe.compute_target_coefficient(timeframe.end);
96 let state =
97 self.device
98 .scale_state(self.previous.clone(), keyframe.get_target(), progress);
99 self.device.set_state(state)?;
100 }
101 };
102
103 Ok(())
104 }
105
106 fn get_best_keyframe<R: Into<Range<u64>>>(&mut self, timeframe: R) -> Option<Keyframe> {
120 let timeframe = timeframe.into();
121 self.keyframes
123 .iter()
124 .filter(|kf| {
125 kf.get_start() >= timeframe.start && kf.get_start() < timeframe.end ||
127 kf.get_end() >= timeframe.start && kf.get_end() < timeframe.end ||
129 kf.get_start() <= timeframe.start && kf.get_end() > timeframe.end
131 })
132 .max_by(|a, b| a.get_end().cmp(&b.get_end()))
133 .cloned()
134 }
135
136 fn update_history(&mut self, new_state: State) {
138 if self.current != new_state {
139 self.previous = self.current.clone();
140 self.current = new_state;
141 }
142 }
143
144 pub fn get_device(&self) -> &dyn Output {
146 &*self.device
147 }
148 pub fn get_keyframes(&self) -> &Vec<Keyframe> {
150 &self.keyframes
151 }
152
153 #[allow(rustdoc::private_intra_doc_links)]
154 pub fn with_keyframe(mut self, keyframe: Keyframe) -> Self {
160 self.keyframes.push(keyframe);
161 self
162 }
163}
164
165impl Display for Track {
166 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
167 write!(
168 f,
169 "Track: {} keyframes - duration: {}ms",
170 self.keyframes.len(),
171 self.get_duration()
172 )
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use crate::animations::Keyframe;
179 use crate::mocks::output_device::MockOutputDevice;
180 use crate::utils::Range;
181
182 use super::*;
183
184 #[test]
185 fn test_new_track() {
186 let actuator = MockOutputDevice::new(5);
187 let track = Track::new(actuator);
188
189 assert_eq!(track.get_keyframes().len(), 0);
190 assert_eq!(track.previous.as_integer(), 5);
191 assert_eq!(track.current.as_integer(), 5);
192
193 let track = track.with_keyframe(Keyframe::new(50, 0, 2000));
194 assert_eq!(track.get_keyframes().len(), 1);
195 }
196
197 #[test]
198 fn test_get_duration() {
199 let actuator = MockOutputDevice::new(5);
200 let track = Track::new(actuator);
201
202 assert_eq!(
203 track.get_duration(),
204 0,
205 "Track with no keyframe have a 0 duration."
206 );
207
208 let track = track
209 .with_keyframe(Keyframe::new(50, 0, 2000))
210 .with_keyframe(Keyframe::new(100, 500, 2200))
211 .with_keyframe(Keyframe::new(100, 100, 1000));
212 assert_eq!(
213 track.get_duration(),
214 2200,
215 "Track duration is the end time of the latest keyframe."
216 );
217 }
218
219 #[test]
220 fn test_update_history() {
221 let actuator = MockOutputDevice::new(5);
222 let mut track = Track::new(actuator);
223 assert_eq!(track.previous.as_integer(), 5);
224 assert_eq!(track.current.as_integer(), 5);
225
226 track.update_history(75.into());
227
228 assert_eq!(track.previous.as_integer(), 5); assert_eq!(track.current.as_integer(), 75); track.update_history(100.into());
232 assert_eq!(track.previous.as_integer(), 75); assert_eq!(track.current.as_integer(), 100); }
235
236 #[test]
237 fn test_get_best_keyframe() {
238 let mut track = Track::new(MockOutputDevice::new(100))
239 .with_keyframe(Keyframe::new(60, 0, 2000))
240 .with_keyframe(Keyframe::new(70, 500, 2200))
241 .with_keyframe(Keyframe::new(80, 100, 2100));
242
243 let keyframe = track.get_best_keyframe([0, 100]);
244 assert!(keyframe.is_some());
245 assert_eq!(keyframe.unwrap().get_target().as_integer(), 60);
246
247 let keyframe = track.get_best_keyframe([300, 400]);
248 assert!(keyframe.is_some());
249 assert_eq!(keyframe.unwrap().get_target().as_integer(), 80);
250
251 let keyframe = track.get_best_keyframe([600, 800]);
252 assert!(keyframe.is_some());
253 assert_eq!(keyframe.unwrap().get_target().as_integer(), 70);
254
255 let keyframe = track.get_best_keyframe([3000, 3200]);
256 assert!(keyframe.is_none());
257 }
258
259 #[test]
260 fn test_play_frame_no_keyframes() {
261 let actuator = MockOutputDevice::new(5);
262 let mut track = Track::new(actuator);
263
264 let result = track.play_frame(Range {
265 start: 0,
266 end: 1000,
267 });
268 assert!(result.is_ok());
269 }
270
271 #[test]
272 fn test_play_frame() {
273 let actuator = MockOutputDevice::new(0);
274 let mut track = Track::new(actuator);
275
276 let result = track.play_frame([500, 1500]);
278 assert!(result.is_ok());
279 assert_eq!(track.previous.as_integer(), 0);
280 assert_eq!(track.current.as_integer(), 0);
281
282 let mut track = track
284 .with_keyframe(Keyframe::new(50, 0, 2000))
285 .with_keyframe(Keyframe::new(70, 500, 2500))
286 .with_keyframe(Keyframe::new(90, 100, 1000));
287
288 let result = track.play_frame([500, 1500]); assert!(result.is_ok());
290 assert_eq!(track.previous.as_integer(), 0);
291 assert_eq!(track.current.as_integer(), 70); assert_eq!(track.get_device().get_state().as_integer(), 35); }
294
295 #[test]
296 fn test_display_implementation() {
297 let track = Track::new(MockOutputDevice::new(5))
298 .with_keyframe(Keyframe::new(50, 0, 2000))
299 .with_keyframe(Keyframe::new(100, 500, 2200))
300 .with_keyframe(Keyframe::new(100, 100, 1000));
301
302 let expected_display = "Track: 3 keyframes - duration: 2200ms";
303 assert_eq!(format!("{}", track), expected_display);
304 }
305}