Skip to main content

animate_core/mode/
once.rs

1use crate::macros::impl_ops;
2use crate::{FRAME, AnimateState, IS_ANIMATING, Lerp};
3use std::sync::atomic::Ordering;
4use std::time::Instant;
5
6#[derive(Debug)]
7pub struct Once<T: Lerp + PartialEq>(pub(crate) AnimateState<T>);
8
9impl<T: Lerp + PartialEq + Default> Once<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 t = (elapsed / self.0.duration).clamp(0.0, 1.0);
35                    *self.0.current.get() = (self.0.interp)(
36                        &*self.0.start.get(),
37                        &*self.0.target.get(),
38                        (self.0.easing)(t),
39                    );
40                    *last_frame = frame;
41                    if t >= 1.0 {
42                        *started_at = None;
43                    } else {
44                        IS_ANIMATING.store(true, Ordering::Relaxed);
45                    }
46                }
47            }
48            &*self.0.current.get()
49        }
50    }
51
52    pub fn target(&self) -> &T {
53        unsafe {
54            if (*self.0.started_at.get()).is_none() {
55                &*self.0.current.get()
56            } else {
57                &*self.0.target.get()
58            }
59        }
60    }
61}
62
63impl_ops!(Once);