use core::ops::{Add, Div, Mul, Sub}; use num_traits::{float::FloatCore, One}; use crate::{Anim, Fun}; /// An `Anim` together with the duration that it is intended to be played for. /// /// Explicitly carrying the duration around makes it easier to sequentially /// compose animations in some places. #[derive(Clone, Debug)] pub struct AnimWithDur(pub Anim, pub F::T); impl Anim where F: Fun, { /// Tag this animation with the duration that it is intended to be played /// for. /// /// Note that using this tagging is completely optional, but it may /// make it easier to combine animations sometimes. pub fn dur(self, t: F::T) -> AnimWithDur { AnimWithDur(self, t) } } impl<'a, V> From<&'a [V]> for AnimWithDur> where V: Clone, { fn from(slice: &'a [V]) -> Self { AnimWithDur(Anim(SliceClosure(slice)), slice.len()) } } pub fn slice<'a, V>(slice: &'a [V]) -> AnimWithDur + 'a> where V: Clone + 'a, { slice.into() } #[doc(hidden)] pub struct SliceClosure<'a, V>(&'a [V]); impl<'a, V> Fun for SliceClosure<'a, V> where V: Clone, { type T = usize; type V = V; fn eval(&self, t: Self::T) -> Self::V { self.0[t].clone() } } impl Anim where F: Fun, F::T: Clone + FloatCore, { pub fn scale_to_dur(self, dur: F::T) -> AnimWithDur> { self.scale_time(F::T::one() / dur).dur(dur) } } impl AnimWithDur where F: Fun, F::T: Clone, { pub fn as_ref(&self) -> AnimWithDur<&F> { AnimWithDur(self.0.as_ref(), self.1.clone()) } } impl AnimWithDur where F: Fun, { pub fn transform(self, h: H) -> AnimWithDur where G: Fun, H: FnOnce(Anim) -> Anim, { AnimWithDur(h(self.0), self.1) } pub fn map(self, f: impl Fn(F::V) -> W) -> AnimWithDur> { self.transform(move |anim| anim.map(f)) } pub fn dur(self, t: F::T) -> AnimWithDur { AnimWithDur(self.0, t) } } impl<'a, T, X, Y, F> AnimWithDur where T: 'a + Clone, X: 'a, Y: 'a, F: Fun, { pub fn unzip( &'a self, ) -> ( AnimWithDur + 'a>, AnimWithDur + 'a>, ) { ( self.as_ref().transform(|anim| anim.fst()), self.as_ref().transform(|anim| anim.snd()), ) } } impl AnimWithDur where F: Fun, F::T: Copy + PartialOrd + Sub, { pub fn seq(self, next: Anim) -> Anim> where G: Fun, { self.0.seq(self.1, next) } } impl AnimWithDur where F: Fun, F::T: Copy + PartialOrd + Sub + Add, { pub fn seq_with_dur(self, next: AnimWithDur) -> AnimWithDur> where G: Fun, { let dur = self.1.clone() + next.1; AnimWithDur(self.seq(next.0), dur) } } impl AnimWithDur where F: Fun, F::T: Clone + FloatCore, { pub fn repeat(self) -> Anim> { self.0.repeat(self.1) } } impl AnimWithDur where F: Fun, F::T: Clone + Sub, { pub fn backwards(self) -> AnimWithDur> { AnimWithDur(self.0.backwards(self.1.clone()), self.1) } } impl AnimWithDur where F: Fun, F::T: Clone + Mul + Div, { pub fn scale_time(self, t_scale: F::T) -> AnimWithDur> { AnimWithDur(self.0.scale_time(t_scale.clone()), self.1 / t_scale) } } #[macro_export] macro_rules! seq_with_dur { ( $expr:expr $(,)? ) => { $expr }; ( $head:expr, $($tail:expr $(,)?)+ ) => { $head.seq_with_dur($crate::seq_with_dur!($($tail,)*)) } }