animate_core/mode/
alternate.rs1use crate::macros::impl_ops;
2use crate::{AnimateState, FRAME, IS_ANIMATING, Lerp};
3use std::sync::atomic::Ordering;
4use std::time::Instant;
5
6#[derive(Debug)]
7pub struct Alternate<T: Lerp + PartialEq>(pub(crate) AnimateState<T>);
8
9impl<T: Lerp + PartialEq + Default> Alternate<T> {
10 pub fn new(
11 initial: T,
12 duration: f64,
13 easing: fn(f64) -> f64,
14 interp: fn(&T, &T, f64) -> T,
15 ) -> Self {
16 Self(AnimateState::new(initial, duration, easing, interp))
17 }
18
19 pub fn set(&mut self, target: T) {
20 let current = std::mem::take(self.0.current.get_mut());
21 *self.0.start.get_mut() = current;
22 *self.0.target.get_mut() = target;
23 *self.0.started_at.get_mut() = Some(Instant::now());
24 }
25
26 pub fn get(&self) -> &T {
27 let frame = FRAME.load(Ordering::Relaxed);
28 unsafe {
29 let last_frame = self.0.last_frame.get();
30 let started_at = self.0.started_at.get();
31 if *last_frame != frame {
32 if let Some(started) = *started_at {
33 let elapsed = started.elapsed().as_secs_f64() * 1000.0;
34 let cycle = (elapsed / self.0.duration) as u64;
35 let t_raw = (elapsed % self.0.duration) / self.0.duration;
36 let t = if cycle % 2 == 0 { t_raw } else { 1.0 - t_raw };
37 *self.0.current.get() = (self.0.interp)(
38 &*self.0.start.get(),
39 &*self.0.target.get(),
40 (self.0.easing)(t),
41 );
42 *last_frame = frame;
43 IS_ANIMATING.store(true, Ordering::Relaxed);
44 }
45 }
46 &*self.0.current.get()
47 }
48 }
49
50 pub fn target(&self) -> &T {
51 unsafe { &*self.0.target.get() }
52 }
53}
54
55impl_ops!(Alternate);