1#![allow(non_snake_case)]
8
9use std::marker::PhantomData;
10
11pub trait Animatable: Sized + Clone {
36 fn animate(&self, to: &Self, time: f64) -> Self;
38}
39
40macro_rules! impl_primitive {
42 ($ty:ident) => {
43 impl Animatable for $ty {
44 #[inline]
45 fn animate(&self, to: &Self, time: f64) -> Self {
46 if time == 0.0 {
47 return *self;
48 }
49 if (1.0 - time).abs() < f64::EPSILON {
50 return *to;
51 }
52 if self == to {
53 return *self;
54 }
55 crate::utils::check_time(time);
56 let v = (*self as f64) * (1.0 - time) + (*to as f64) * time;
57 if *to >= *self {
58 (v + 0.5) as Self
59 } else {
60 (v - 0.5) as Self
61 }
62 }
63 }
64 };
65 ($ty:ident, float) => {
66 impl Animatable for $ty {
67 #[inline]
68 fn animate(&self, to: &Self, time: f64) -> Self {
69 if time == 0.0 {
70 return *self;
71 }
72 if (1.0 - time).abs() < f64::EPSILON {
73 return *to;
74 }
75 if (self - to).abs() < $ty::EPSILON {
76 return *self;
77 }
78 crate::utils::check_time(time);
79 let v = (*self as f64) * (1.0 - time) + (*to as f64) * time;
81 v as Self
82 }
83 }
84 };
85}
86
87impl_primitive!(u8);
88impl_primitive!(u16);
89impl_primitive!(u32);
90impl_primitive!(u64);
91impl_primitive!(u128);
92impl_primitive!(usize);
93impl_primitive!(i8);
94impl_primitive!(i16);
95impl_primitive!(i32);
96impl_primitive!(i64);
97impl_primitive!(i128);
98impl_primitive!(isize);
99impl_primitive!(f32, float);
100impl_primitive!(f64, float);
101
102impl Animatable for bool {
103 #[inline]
104 fn animate(&self, to: &Self, time: f64) -> Self {
105 if time < 1.0 {
106 *self
107 } else {
108 *to
109 }
110 }
111}
112
113impl Animatable for char {
114 #[inline]
115 fn animate(&self, to: &Self, time: f64) -> Self {
116 if self == to {
117 return *self;
118 }
119
120 let from_idx = *self as u32;
121 let to_idx = *to as u32;
122 let idx = from_idx.animate(&to_idx, time);
123 let n = if from_idx > to_idx {
124 from_idx - idx
125 } else {
126 idx - from_idx
127 };
128 let mut rng = *self..=*to;
129 match rng.nth(n as usize) {
130 Some(c) => c,
131 None => *self,
132 }
133 }
134}
135
136impl Animatable for () {
137 #[inline]
138 fn animate(&self, _to: &Self, _time: f64) -> Self {}
139}
140
141impl<T> Animatable for PhantomData<T> {
142 #[inline]
143 fn animate(&self, _to: &Self, _time: f64) -> Self {
144 Default::default()
145 }
146}
147
148impl<T: Animatable> Animatable for Option<T> {
149 #[inline]
150 fn animate(&self, to: &Self, time: f64) -> Self {
151 match (self, to) {
152 (Some(a), Some(b)) => Some(a.animate(b, time)),
153 _ => None,
154 }
155 }
156}
157
158impl<T: Animatable, const N: usize> Animatable for [T; N] {
159 #[inline]
160 fn animate(&self, to: &Self, time: f64) -> Self {
161 let mut res = self.clone();
162 self.iter()
163 .zip(to.iter())
164 .zip(res.iter_mut())
165 .for_each(|((a, b), c)| *c = a.animate(b, time));
166 res
167 }
168}
169
170macro_rules! impl_tuple {
173 ($($n:tt $name:ident)+) => {
174 impl<'de, $($name,)+> Animatable for ($($name,)+)
175 where
176 $($name: Animatable,)+
177 {
178 #[inline]
179 fn animate(&self, to: &Self, time: f64) -> Self
180 {
181 $(
182 let $name = Animatable::animate(&self.$n, &to.$n, time);
183 )+
184 ($($name,)+)
185 }
186 }
187 }
188}
189
190impl_tuple!(0 T0);
191impl_tuple!(0 T0 1 T1);
192impl_tuple!(0 T0 1 T1 2 T2);
193impl_tuple!(0 T0 1 T1 2 T2 3 T3);
194impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4);
195impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5);
196impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6);
197impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7);
198impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8);
199impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9);
200impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10);
201impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11);
202impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12);
203impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13);
204impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14);
205impl_tuple!(0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15);
206
207#[cfg(test)]
208mod test {
209 use crate::Animatable;
210
211 #[test]
212 fn test_bool() {
213 let v = false.animate(&true, 0.0);
214 assert!(v == false);
215
216 let v = false.animate(&true, 0.5);
217 assert!(v == false);
218
219 let v = false.animate(&true, 1.0);
220 assert!(v == true);
221
222 let v = true.animate(&true, 0.3);
223 assert!(v == true);
224
225 let v = false.animate(&false, 0.2);
226 assert!(v == false);
227 }
228
229 #[test]
230 fn test_char() {
231 let v = 'a'.animate(&'e', 0.0);
232 assert_eq!(v, 'a');
233
234 let v = 'a'.animate(&'e', 0.5);
235 assert_eq!(v, 'c');
236
237 let v = 'a'.animate(&'e', 0.555);
238 assert_eq!(v, 'c');
239
240 let v = 'a'.animate(&'e', 1.0);
241 assert_eq!(v, 'e');
242 }
243}