use super::BaseAnimation;
use crate::DURATION_ZERO;
use std::time::Duration;
pub trait Cursor {
type Item;
fn size(&self) -> Option<usize>;
fn index(&self, n: usize) -> Self::Item;
}
impl<T: Clone> Cursor for [T] {
type Item = T;
#[inline]
fn size(&self) -> Option<usize> {
Some(self.len())
}
#[inline]
fn index(&self, n: usize) -> T {
self[n].to_owned()
}
}
impl<T: Clone> Cursor for &[T] {
type Item = T;
#[inline]
fn size(&self) -> Option<usize> {
Some(self.len())
}
#[inline]
fn index(&self, n: usize) -> T {
self[n].to_owned()
}
}
impl<T: Clone> Cursor for Vec<T> {
type Item = T;
#[inline]
fn size(&self) -> Option<usize> {
Some(self.len())
}
#[inline]
fn index(&self, n: usize) -> T {
self[n].to_owned()
}
}
impl<T: Cursor> Cursor for &T {
type Item = T::Item;
#[inline]
fn size(&self) -> Option<usize> {
(**self).size()
}
#[inline]
fn index(&self, n: usize) -> Self::Item {
(**self).index(n)
}
}
impl<T: Cursor> Cursor for Box<T> {
type Item = T::Item;
#[inline]
fn size(&self) -> Option<usize> {
(**self).size()
}
#[inline]
fn index(&self, n: usize) -> Self::Item {
(**self).index(n)
}
}
struct Finite<T> {
src: T,
}
impl<T> Cursor for Finite<T>
where
T: ExactSizeIterator + Clone,
{
type Item = <T as Iterator>::Item;
#[inline]
fn size(&self) -> Option<usize> {
self.src.len().into()
}
#[inline]
fn index(&self, n: usize) -> Self::Item {
let mut src = self.src.clone();
src.nth(n).unwrap()
}
}
impl<T> From<T> for Finite<T>
where
T: ExactSizeIterator + Clone,
{
#[inline]
fn from(src: T) -> Self {
Finite { src }
}
}
#[derive(Clone)]
pub struct Infinite<F: Fn(usize) -> T, T> {
f: F,
}
impl<F, T> Infinite<F, T>
where
F: Fn(usize) -> T,
{
#[inline]
pub(super) fn new(f: F) -> Self {
Self { f }
}
}
impl<F, T> Cursor for Infinite<F, T>
where
F: Fn(usize) -> T,
{
type Item = T;
#[inline]
fn size(&self) -> Option<usize> {
None
}
#[inline]
fn index(&self, n: usize) -> Self::Item {
(self.f)(n)
}
}
#[derive(Debug, Clone)]
pub struct StepAnimation<T: Cursor> {
src: T,
interval: Duration,
}
impl<T> StepAnimation<T>
where
T: Cursor,
{
#[inline]
pub(super) fn new(src: T) -> Self {
Self {
src,
interval: DURATION_ZERO,
}
}
#[inline]
pub fn interval(mut self, interval: Duration) -> Self {
self.interval = interval;
self
}
}
impl<T> BaseAnimation for StepAnimation<T>
where
T: Cursor,
{
type Item = <T as Cursor>::Item;
#[inline]
fn duration(&self) -> Option<Duration> {
if self.interval == DURATION_ZERO {
return Some(DURATION_ZERO);
}
self.src
.size()
.map(|size| self.interval.mul_f64(size as f64))
}
#[inline]
fn animate(&self, elapsed: Duration) -> Self::Item {
let n = match self.duration() {
Some(duration) if duration == DURATION_ZERO => 0,
Some(duration) if elapsed >= duration => self.src.size().unwrap(),
_ => {
let n = elapsed.as_secs_f64() / self.interval.as_secs_f64();
n as usize
}
};
self.src.index(n)
}
}