#![doc(html_root_url = "https://coriolinus.github.io/lerp-rs/")]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
use num_traits::{Float, One, Zero};
use std::iter;
use std::iter::{Chain, Once, Skip};
use std::ops::{Add, Mul};
pub use num_traits;
pub trait Lerp<F> {
fn lerp(self, other: Self, t: F) -> Self;
fn lerp_bounded(self, other: Self, t: F) -> Self
where
Self: Sized,
F: PartialOrd + Copy + Zero + One,
{
let t = match t {
t if t < F::zero() => F::zero(),
t if t > F::one() => F::one(),
t => t,
};
self.lerp(other, t)
}
fn lerp_to(&mut self, other: Self, t: F)
where
Self: Sized + Copy,
{
*self = self.lerp(other, t);
}
fn lerp_bounded_to(&mut self, other: Self, t: F)
where
Self: Sized + Copy,
F: PartialOrd + Copy + Zero + One,
{
*self = self.lerp_bounded(other, t);
}
}
pub trait LerpIter {
fn lerp_iter(self, other: Self, steps: usize) -> LerpIterator<Self>
where
Self: Sized;
fn lerp_iter_closed(
self,
other: Self,
steps: usize,
) -> Skip<Chain<LerpIterator<Self>, Once<Self>>>
where
Self: Copy,
LerpIterator<Self>: Iterator<Item = Self>,
{
if steps == 0 {
LerpIterator::new(self, other, steps)
.chain(iter::once(other))
.skip(1)
} else {
LerpIterator::new(self, other, steps - 1)
.chain(iter::once(other))
.skip(0)
}
}
}
impl<T, F> Lerp<F> for T
where
T: Add<Output = T> + Mul<F, Output = T>,
F: Float,
{
fn lerp(self, other: T, t: F) -> T {
self * (F::one() - t) + other * t
}
}
impl<T> LerpIter for T
where
T: Lerp<f64> + Sized,
{
fn lerp_iter(self, other: T, steps: usize) -> LerpIterator<T> {
LerpIterator::new(self, other, steps)
}
}
pub struct LerpIterator<T> {
begin: T,
end: T,
steps: usize,
current_step: usize,
}
impl<T> LerpIterator<T> {
fn new(begin: T, end: T, steps: usize) -> LerpIterator<T> {
LerpIterator {
begin,
end,
steps,
current_step: 0,
}
}
}
impl<T> Iterator for LerpIterator<T>
where
T: Lerp<f64> + Copy,
{
type Item = T;
fn next(&mut self) -> Option<T> {
if self.current_step >= self.steps {
None
} else {
let t = self.current_step as f64 / self.steps as f64;
self.current_step += 1;
Some(self.begin.lerp(self.end, t))
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let remaining = if self.current_step >= self.steps {
0
} else {
self.steps - self.current_step
};
(remaining, Some(remaining))
}
}
impl<T> ExactSizeIterator for LerpIterator<T> where T: Lerp<f64> + Copy {}
#[cfg(feature = "derive")]
#[allow(unused_imports)]
#[macro_use]
extern crate lerp_derive;
#[cfg(feature = "derive")]
#[doc(hidden)]
pub use lerp_derive::*;