use crate::Time;
use std::fmt::Debug;
pub trait Animated<T, X: Time> {
fn get(&self, time: X) -> T;
fn is_finished(&self, time: X) -> bool;
fn map<R, F: Fn(T) -> R>(self, map: F) -> AnimatedMap<T, X, Self, R, F>
where
Self: Sized,
{
AnimatedMap::new(self, map)
}
fn join<T2, A2: Animated<T2, X>>(self, other: A2) -> AnimatedJoin<T, T2, X, Self, A2>
where
Self: Sized,
{
AnimatedJoin::new(self, other)
}
fn flatten<R>(self) -> AnimatedFlatten<R, X, T, Self>
where
Self: Sized,
T: Animated<R, X>,
{
AnimatedFlatten::new(self)
}
}
impl<X: Time> Animated<(), X> for () {
fn get(&self, _time: X) {}
fn is_finished(&self, _time: X) -> bool {
true
}
}
impl<V, T, X: Time> Animated<(V,), X> for (T,)
where
T: Animated<V, X>,
{
fn get(&self, time: X) -> (V,) {
(self.0.get(time),)
}
fn is_finished(&self, time: X) -> bool {
self.0.is_finished(time)
}
}
impl<V1, V2, T1, T2, X: Time> Animated<(V1, V2), X> for (T1, T2)
where
T1: Animated<V1, X>,
T2: Animated<V2, X>,
{
fn get(&self, time: X) -> (V1, V2) {
(self.0.get(time), self.1.get(time))
}
fn is_finished(&self, time: X) -> bool {
self.0.is_finished(time) && self.1.is_finished(time)
}
}
impl<V1, V2, V3, T1, T2, T3, X: Time> Animated<(V1, V2, V3), X> for (T1, T2, T3)
where
T1: Animated<V1, X>,
T2: Animated<V2, X>,
T3: Animated<V3, X>,
{
fn get(&self, time: X) -> (V1, V2, V3) {
(self.0.get(time), self.1.get(time), self.2.get(time))
}
fn is_finished(&self, time: X) -> bool {
self.0.is_finished(time) && self.1.is_finished(time) && self.2.is_finished(time)
}
}
impl<V1, V2, V3, V4, T1, T2, T3, T4, X: Time> Animated<(V1, V2, V3, V4), X> for (T1, T2, T3, T4)
where
T1: Animated<V1, X>,
T2: Animated<V2, X>,
T3: Animated<V3, X>,
T4: Animated<V4, X>,
{
fn get(&self, time: X) -> (V1, V2, V3, V4) {
(
self.0.get(time),
self.1.get(time),
self.2.get(time),
self.3.get(time),
)
}
fn is_finished(&self, time: X) -> bool {
self.0.is_finished(time)
&& self.1.is_finished(time)
&& self.2.is_finished(time)
&& self.3.is_finished(time)
}
}
impl<T: Clone + Copy + Default, X: Time, I: Animated<T, X>, const S: usize> Animated<[T; S], X>
for [I; S]
{
fn get(&self, time: X) -> [T; S] {
let mut result: [T; S] = [Default::default(); S];
for i in 0..S {
result[i] = self[i].get(time);
}
result
}
fn is_finished(&self, time: X) -> bool {
self.iter().all(|i| i.is_finished(time))
}
}
pub struct AnimatedMap<T, X: Time, A: Animated<T, X>, R, F: Fn(T) -> R> {
animated: A,
map: F,
phantom: std::marker::PhantomData<(T, X)>,
}
impl<T, X: Time, A: Animated<T, X>, R, F: Fn(T) -> R> AnimatedMap<T, X, A, R, F> {
pub fn new(animated: A, map: F) -> Self {
Self {
animated,
map,
phantom: Default::default(),
}
}
}
impl<T, X: Time, A: Animated<T, X>, R, F: Fn(T) -> R> Animated<R, X>
for AnimatedMap<T, X, A, R, F>
{
fn get(&self, time: X) -> R {
(self.map)(self.animated.get(time))
}
fn is_finished(&self, time: X) -> bool {
self.animated.is_finished(time)
}
}
impl<T, X: Time, A: Animated<T, X>, R, F: Fn(T) -> R> Clone for AnimatedMap<T, X, A, R, F>
where
A: Clone,
F: Clone,
{
fn clone(&self) -> Self {
Self {
animated: self.animated.clone(),
map: self.map.clone(),
phantom: Default::default(),
}
}
}
impl<T, X: Time, A: Animated<T, X>, R, F: Fn(T) -> R> Debug for AnimatedMap<T, X, A, R, F>
where
A: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AnimatedMap")
.field("animated", &self.animated)
.field("map", &"Fn(T) -> R")
.finish()
}
}
pub struct AnimatedJoin<T1, T2, X: Time, A1: Animated<T1, X>, A2: Animated<T2, X>> {
animated1: A1,
animated2: A2,
phantom: std::marker::PhantomData<(T1, T2, X)>,
}
impl<T1, T2, X: Time, A1: Animated<T1, X>, A2: Animated<T2, X>> AnimatedJoin<T1, T2, X, A1, A2> {
pub fn new(animated1: A1, animated2: A2) -> Self {
Self {
animated1,
animated2,
phantom: Default::default(),
}
}
}
impl<T1, T2, X: Time, A1: Animated<T1, X>, A2: Animated<T2, X>> Animated<(T1, T2), X>
for AnimatedJoin<T1, T2, X, A1, A2>
{
fn get(&self, time: X) -> (T1, T2) {
(self.animated1.get(time), self.animated2.get(time))
}
fn is_finished(&self, time: X) -> bool {
self.animated1.is_finished(time) && self.animated2.is_finished(time)
}
}
impl<T1, T2, X: Time, A1: Animated<T1, X> + Clone, A2: Animated<T2, X> + Clone> Clone
for AnimatedJoin<T1, T2, X, A1, A2>
{
fn clone(&self) -> Self {
Self {
animated1: self.animated1.clone(),
animated2: self.animated2.clone(),
phantom: Default::default(),
}
}
}
impl<T1, T2, X: Time, A1: Animated<T1, X> + Copy, A2: Animated<T2, X> + Copy> Copy
for AnimatedJoin<T1, T2, X, A1, A2>
{
}
impl<T1, T2, X: Time, A1: Animated<T1, X> + Debug, A2: Animated<T2, X> + Debug> Debug
for AnimatedJoin<T1, T2, X, A1, A2>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AnimatedJoin")
.field("animated1", &self.animated1)
.field("animated2", &self.animated2)
.finish()
}
}
pub struct AnimatedFlatten<T, X: Time, A: Animated<T, X>, AG: Animated<A, X>> {
animated: AG,
phantom: std::marker::PhantomData<(T, X, A)>,
}
impl<T, X: Time, A: Animated<T, X>, AG: Animated<A, X>> AnimatedFlatten<T, X, A, AG> {
pub fn new(animated: AG) -> Self {
Self {
animated,
phantom: Default::default(),
}
}
}
impl<T, X: Time, A: Animated<T, X>, AG: Animated<A, X>> Animated<T, X>
for AnimatedFlatten<T, X, A, AG>
{
fn get(&self, time: X) -> T {
self.animated.get(time).get(time)
}
fn is_finished(&self, time: X) -> bool {
self.animated.is_finished(time) && self.animated.get(time).is_finished(time)
}
}
impl<T, X: Time, A: Animated<T, X>, AG: Animated<A, X> + Clone> Clone
for AnimatedFlatten<T, X, A, AG>
{
fn clone(&self) -> Self {
Self {
animated: self.animated.clone(),
phantom: Default::default(),
}
}
}
impl<T, X: Time, A: Animated<T, X>, AG: Animated<A, X> + Copy> Copy
for AnimatedFlatten<T, X, A, AG>
{
}
impl<T, X: Time, A: Animated<T, X>, AG: Animated<A, X> + Debug> Debug
for AnimatedFlatten<T, X, A, AG>
where
A: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AnimatedFlatten")
.field("animated", &self.animated)
.finish()
}
}
#[cfg(test)]
mod test {
use super::*;
use crate as glissade;
use crate::Mix;
use crate::{keyframes, Keyframes};
#[derive(Clone, Copy, Debug, PartialEq, Mix)]
struct TestItem(f32);
#[test]
fn animated_map() {
let animated = keyframes::from(TestItem(0.0))
.go_to(TestItem(1.0), 1.0)
.run(0.0)
.map(|item| (item.0 * 10.0) as i32);
assert_eq!(animated.get(0.0), 0);
assert_eq!(animated.get(0.5), 5);
assert_eq!(animated.get(1.0), 10);
}
#[test]
fn animated_join() {
let animated1 = keyframes::from(TestItem(0.0))
.go_to(TestItem(1.0), 1.0)
.run(0.0)
.map(|i| i.0);
let animated2 = keyframes::from(TestItem(3.0))
.go_to(TestItem(4.0), 2.0)
.run(0.0)
.map(|i| i.0);
let animated = animated1.join(animated2);
assert_eq!(animated.get(0.0), (0.0, 3.0));
assert_eq!(animated.get(0.5), (0.5, 3.25));
assert_eq!(animated.get(1.0), (1.0, 3.5));
assert_eq!(animated.get(1.5), (1.0, 3.75));
assert_eq!(animated.get(2.0), (1.0, 4.0));
assert!(!animated.is_finished(0.0));
assert!(!animated.is_finished(1.0));
assert!(!animated.is_finished(1.5));
assert!(animated.is_finished(2.0));
assert!(animated.is_finished(3.0));
}
#[test]
fn animated_flatten() {
let animated = keyframes::from(0.0)
.go_to(2.0, 1.0)
.run(0.0)
.map(|i| keyframes::from(i).go_to(4.0, 1.0).run(0.0))
.flatten();
assert_eq!(animated.get(0.0), 0.0);
assert_eq!(animated.get(0.25), 1.375);
assert_eq!(animated.get(0.5), 2.5);
assert_eq!(animated.get(0.75), 3.375);
assert_eq!(animated.get(1.0), 4.0);
assert_eq!(animated.get(1.5), 4.0);
assert_eq!(animated.get(2.0), 4.0);
assert_eq!(animated.get(3.0), 4.0);
}
}