use crate::{Animation, Easing, Mix, Time, TimeDiff};
use std::fmt::Debug;
use std::marker::PhantomData;
pub trait Keyframes<T: Clone + Mix + PartialEq, X: Time> {
fn get(&self, offset: X::Duration) -> T;
fn duration(&self) -> X::Duration;
fn is_finished(&self, offset: X::Duration) -> bool {
offset >= self.duration()
}
fn is_infinite(&self) -> bool {
false
}
fn is_finite(&self) -> bool {
!self.is_infinite()
}
fn start_value(&self) -> T {
self.get(Default::default())
}
fn end_value(&self) -> T {
self.get(self.duration())
}
fn stay(self, duration: X::Duration) -> SequentialKeyframes<T, X, Self, NoneKeyframes<T, X>>
where
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(self, NoneKeyframes::new(end_value, duration))
}
fn go_to(
self,
target: T,
duration: X::Duration,
) -> SequentialKeyframes<T, X, Self, LinearKeyframes<T, X>>
where
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(self, LinearKeyframes::new(end_value, target, duration))
}
fn ease_to(
self,
target: T,
duration: X::Duration,
easing: Easing,
) -> SequentialKeyframes<T, X, Self, EasingKeyframes<T, X>>
where
Self: Sized,
{
let end_value = self.end_value();
SequentialKeyframes::new(
self,
EasingKeyframes::new(end_value, target, duration, easing),
)
}
fn repeat(self) -> RepeatKeyframes<T, X, Self>
where
Self: Sized,
{
RepeatKeyframes::new(self)
}
fn repeat_n(self, n: f32) -> RepeatNKeyframes<T, X, Self>
where
Self: Sized,
{
RepeatNKeyframes::new(self, n)
}
fn reverse(self) -> ReverseKeyframes<T, X, Self>
where
Self: Sized,
{
ReverseKeyframes::new(self)
}
fn scale(self, scale: f32) -> ScaleKeyframes<T, X, Self>
where
Self: Sized,
{
ScaleKeyframes::new(self, scale)
}
fn scale_to(self, new_duration: X::Duration) -> ScaleKeyframes<T, X, Self>
where
Self: Sized,
{
let scale = if self.duration() == Default::default() {
1.0
} else {
new_duration.as_f32() / self.duration().as_f32()
};
ScaleKeyframes::new(self, scale)
}
fn then<S: Keyframes<T, X>>(self, other: S) -> SequentialKeyframes<T, X, Self, S>
where
Self: Sized,
{
SequentialKeyframes::new(self, other)
}
fn run(self, start_time: X) -> Animation<T, X, Self>
where
Self: Sized,
{
Animation::start(self, start_time)
}
}
pub fn keyframes<T: Mix + Clone + PartialEq, X: Time>(start_value: T) -> NoneKeyframes<T, X> {
NoneKeyframes::new(start_value, Default::default())
}
#[derive(Clone, PartialEq)]
pub struct NoneKeyframes<T: Clone + Mix + PartialEq, X: Time> {
value: T,
duration: X::Duration,
}
impl<T: Clone + Mix + PartialEq + Debug, X: Time> Debug for NoneKeyframes<T, X>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NoneKeyframes")
.field("value", &self.value)
.field("duration", &self.duration)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time> NoneKeyframes<T, X> {
pub fn new(value: T, duration: X::Duration) -> Self {
Self { value, duration }
}
}
impl<T: Clone + Mix + PartialEq, X: Time> Keyframes<T, X> for NoneKeyframes<T, X> {
fn get(&self, _offset: X::Duration) -> T {
self.value.clone()
}
fn duration(&self) -> X::Duration {
self.duration
}
}
impl<T: Clone + Mix + PartialEq + Copy, X: Time> Copy for NoneKeyframes<T, X> {}
#[derive(Clone, PartialEq)]
pub struct LinearKeyframes<T: Mix + Clone + PartialEq, X: Time> {
v1: T,
v2: T,
duration: X::Duration,
}
impl<T: Mix + Clone + PartialEq + Debug, X: Time> Debug for LinearKeyframes<T, X>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LinearKeyframes")
.field("v1", &self.v1)
.field("v2", &self.v2)
.field("duration", &self.duration)
.finish()
}
}
impl<T: Mix + Clone + PartialEq, X: Time> LinearKeyframes<T, X> {
pub fn new(v1: T, v2: T, duration: X::Duration) -> Self {
Self { v1, v2, duration }
}
}
impl<T: Mix + Clone + PartialEq, X: Time> Keyframes<T, X> for LinearKeyframes<T, X> {
fn get(&self, offset: X::Duration) -> T {
let t = offset.as_f32() / self.duration.as_f32();
self.v1.clone().mix(self.v2.clone(), t)
}
fn duration(&self) -> X::Duration {
self.duration
}
}
impl<T: Mix + Clone + PartialEq + Copy, X: Time> Copy for LinearKeyframes<T, X> {}
#[derive(Clone, PartialEq)]
pub struct SequentialKeyframes<
T: Clone + Mix + PartialEq,
X: Time,
S1: Keyframes<T, X>,
S2: Keyframes<T, X>,
> {
t1: S1,
t2: S2,
phantom: PhantomData<(T, X)>,
}
impl<
T: Clone + Mix + PartialEq,
X: Time,
S1: Keyframes<T, X> + Debug,
S2: Keyframes<T, X> + Debug,
> Debug for SequentialKeyframes<T, X, S1, S2>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("SequentialKeyframes")
.field("t1", &self.t1)
.field("t2", &self.t2)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S1: Keyframes<T, X>, S2: Keyframes<T, X>> Keyframes<T, X>
for SequentialKeyframes<T, X, S1, S2>
{
fn get(&self, offset: X::Duration) -> T {
let t1 = self.t1.duration();
if offset < t1 {
self.t1.get(offset)
} else {
self.t2.get(offset.sub(t1))
}
}
fn duration(&self) -> X::Duration {
self.t1.duration().add(self.t2.duration())
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S1: Keyframes<T, X>, S2: Keyframes<T, X>>
SequentialKeyframes<T, X, S1, S2>
{
pub fn new(t1: S1, t2: S2) -> Self {
Self {
t1,
t2,
phantom: Default::default(),
}
}
}
impl<
T: Clone + Mix + PartialEq,
X: Time,
S1: Keyframes<T, X> + Copy,
S2: Keyframes<T, X> + Copy,
> Copy for SequentialKeyframes<T, X, S1, S2>
{
}
#[derive(Clone, PartialEq)]
pub struct EasingKeyframes<T: Mix + Clone + PartialEq, X: Time> {
v1: T,
v2: T,
duration: X::Duration,
easing: Easing,
}
impl<T: Mix + Clone + PartialEq + Debug, X: Time> Debug for EasingKeyframes<T, X>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("EasingKeyframes")
.field("v1", &self.v1)
.field("v2", &self.v2)
.field("duration", &self.duration)
.field("easing", &self.easing)
.finish()
}
}
impl<T: Mix + Clone + PartialEq, X: Time> EasingKeyframes<T, X> {
pub fn new(v1: T, v2: T, duration: X::Duration, easing: Easing) -> Self {
Self {
v1,
v2,
duration,
easing,
}
}
}
impl<T: Mix + Clone + PartialEq, X: Time> Keyframes<T, X> for EasingKeyframes<T, X> {
fn get(&self, offset: X::Duration) -> T {
let t = self.easing.ease(offset.as_f32() / self.duration.as_f32());
self.v1.clone().mix(self.v2.clone(), t)
}
fn duration(&self) -> X::Duration {
self.duration
}
}
#[derive(Clone, PartialEq)]
pub struct RepeatKeyframes<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> {
keyframes: S,
phantom: PhantomData<(T, X)>,
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Debug> Debug
for RepeatKeyframes<T, X, S>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RepeatKeyframes")
.field("keyframes", &self.keyframes)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> RepeatKeyframes<T, X, S> {
pub fn new(keyframes: S) -> Self {
Self {
keyframes,
phantom: Default::default(),
}
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> Keyframes<T, X>
for RepeatKeyframes<T, X, S>
{
fn get(&self, offset: X::Duration) -> T {
let scale = offset.as_f32() / self.keyframes.duration().as_f32();
self.keyframes.get(self.keyframes.duration().scale(scale))
}
fn duration(&self) -> X::Duration {
panic!("RepeatKeyframes has infinite duration");
}
fn is_finished(&self, _offset: X::Duration) -> bool {
false
}
fn is_infinite(&self) -> bool {
true
}
fn end_value(&self) -> T {
panic!("RepeatKeyframes has no end value");
}
}
impl<T: Clone + Copy + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Copy> Copy
for RepeatKeyframes<T, X, S>
{
}
#[derive(Clone, PartialEq)]
pub struct RepeatNKeyframes<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> {
keyframes: S,
n: f32,
phantom: PhantomData<(T, X)>,
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Debug> Debug
for RepeatNKeyframes<T, X, S>
where
X::Duration: Debug,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RepeatNKeyframes")
.field("keyframes", &self.keyframes)
.field("n", &self.n)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> RepeatNKeyframes<T, X, S> {
pub fn new(keyframes: S, n: f32) -> Self {
Self {
keyframes,
n,
phantom: Default::default(),
}
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> Keyframes<T, X>
for RepeatNKeyframes<T, X, S>
{
fn get(&self, offset: X::Duration) -> T {
let duration = self.keyframes.duration().as_f32();
let n = offset.as_f32() / duration;
if n < self.n {
self.keyframes
.get(offset.sub(self.keyframes.duration().scale(n.floor())))
} else {
self.keyframes.end_value()
}
}
fn duration(&self) -> X::Duration {
self.keyframes.duration().scale(self.n)
}
}
impl<T: Clone + Copy + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Copy> Copy
for RepeatNKeyframes<T, X, S>
{
}
#[derive(Clone, PartialEq)]
pub struct ReverseKeyframes<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> {
keyframes: S,
phantom: PhantomData<(T, X)>,
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Debug> Debug
for ReverseKeyframes<T, X, S>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReverseKeyframes")
.field("keyframes", &self.keyframes)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> ReverseKeyframes<T, X, S> {
pub fn new(keyframes: S) -> Self {
Self {
keyframes,
phantom: Default::default(),
}
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> Keyframes<T, X>
for ReverseKeyframes<T, X, S>
{
fn get(&self, offset: X::Duration) -> T {
self.keyframes.get(self.keyframes.duration().sub(offset))
}
fn duration(&self) -> X::Duration {
self.keyframes.duration()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Copy> Copy
for ReverseKeyframes<T, X, S>
{
}
#[derive(Clone, PartialEq)]
pub struct ScaleKeyframes<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> {
keyframes: S,
scale: f32,
phantom: PhantomData<(T, X)>,
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X> + Debug> Debug
for ScaleKeyframes<T, X, S>
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ScaleKeyframes")
.field("keyframes", &self.keyframes)
.field("scale", &self.scale)
.finish()
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> ScaleKeyframes<T, X, S> {
pub fn new(keyframes: S, scale: f32) -> Self {
Self {
keyframes,
scale,
phantom: Default::default(),
}
}
}
impl<T: Clone + Mix + PartialEq, X: Time, S: Keyframes<T, X>> Keyframes<T, X>
for ScaleKeyframes<T, X, S>
{
fn get(&self, offset: X::Duration) -> T {
self.keyframes.get(offset.scale(self.scale))
}
fn duration(&self) -> X::Duration {
self.keyframes.duration().scale(self.scale)
}
}
impl<T: Clone + Mix + PartialEq + Copy, X: Time, S: Keyframes<T, X> + Copy> Copy
for ScaleKeyframes<T, X, S>
{
}
#[cfg(test)]
mod tests {
use super::*;
use crate::easing::Easing;
use crate::mix::Mix;
use std::time::{Duration, Instant};
#[derive(Clone, Copy, Debug, PartialEq)]
struct TestItem(f32);
impl Mix for TestItem {
fn mix(self, other: Self, t: f32) -> Self {
TestItem(self.0.mix(other.0, t))
}
}
const ZERO_DURATION: Duration = Duration::from_secs(0);
const ONE_SECOND: Duration = Duration::from_secs(1);
const HALF_SECOND: Duration = Duration::from_millis(500);
const ONE_AND_HALF_SECONDS: Duration = Duration::from_millis(1500);
const TWO_SECONDS: Duration = Duration::from_secs(2);
#[test]
fn none_keyframes() {
let keyframes: NoneKeyframes<TestItem, Instant> =
NoneKeyframes::new(TestItem(0.0), Duration::from_secs(1));
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.0));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(0.0));
}
#[test]
fn linear_keyframes() {
let keyframes =
LinearKeyframes::<TestItem, Instant>::new(TestItem(0.0), TestItem(1.0), ONE_SECOND);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
}
#[test]
fn sequential_keyframes() {
let keyframes = SequentialKeyframes::new(
LinearKeyframes::<TestItem, Instant>::new(TestItem(0.0), TestItem(1.0), ONE_SECOND),
LinearKeyframes::new(TestItem(1.0), TestItem(0.0), ONE_SECOND),
);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
assert_eq!(keyframes.get(ONE_AND_HALF_SECONDS), TestItem(0.5));
assert_eq!(keyframes.get(TWO_SECONDS), TestItem(0.0));
}
#[test]
fn easing_keyframes() {
let keyframes = EasingKeyframes::<TestItem, Instant>::new(
TestItem(0.0),
TestItem(1.0),
ONE_SECOND,
Easing::QuadraticIn,
);
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(0.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.25));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(1.0));
}
#[test]
fn reversed_keyframes() {
let keyframes = keyframes::<TestItem, Instant>(TestItem(0.0))
.go_to(TestItem(1.0), ONE_SECOND)
.reverse();
assert_eq!(keyframes.get(ZERO_DURATION), TestItem(1.0));
assert_eq!(keyframes.get(HALF_SECOND), TestItem(0.5));
assert_eq!(keyframes.get(ONE_SECOND), TestItem(0.0));
}
}