use core::num::Wrapping;
use core::ops::*;
use core::cmp;
use num_traits::{Zero, One, FloatConst, Signed};
pub fn partial_min<T: PartialOrd + Sized>(a: T, b: T) -> T {
if a <= b { a } else { b }
}
pub fn partial_max<T: PartialOrd + Sized>(a: T, b: T) -> T {
if a >= b { a } else { b }
}
pub trait Clamp<Bound=Self>: Sized {
type BoolVector;
fn clamped(self, lower: Bound, upper: Bound) -> Self;
fn clamp(val: Self, lower: Bound, upper: Bound) -> Self {
val.clamped(lower, upper)
}
fn is_between(self, lower: Bound, upper: Bound) -> Self::BoolVector;
fn clamped01(self) -> Self where Bound: Zero + One {
self.clamped(Bound::zero(), Bound::one())
}
fn clamp01(val: Self) -> Self where Bound: Zero + One {
Self::clamp(val, Bound::zero(), Bound::one())
}
fn is_between01(self) -> Self::BoolVector where Bound: Zero + One {
self.is_between(Bound::zero(), Bound::one())
}
}
macro_rules! impl_clamp_float {
($($T:ty)+) => {
$(
impl Clamp for $T {
type BoolVector = bool;
fn clamped(self, lower: Self, upper: Self) -> Self {
partial_min(partial_max(self, lower), upper)
}
fn is_between(self, lower: Self, upper: Self) -> bool {
lower <= self && self <= upper
}
}
)+
}
}
macro_rules! impl_clamp_integer {
($($T:ty)+) => {
$(
impl Clamp for $T {
type BoolVector = bool;
fn clamped(self, lower: Self, upper: Self) -> Self {
cmp::min(cmp::max(self, lower), upper)
}
fn is_between(self, lower: Self, upper: Self) -> bool {
lower <= self && self <= upper
}
}
)+
}
}
impl_clamp_float!{
f32 f64
}
impl_clamp_integer!{
i8 i16 i32 i64 isize u8 u16 u32 u64 usize
Wrapping<i8>
Wrapping<i16>
Wrapping<i32>
Wrapping<i64>
Wrapping<isize>
Wrapping<u8>
Wrapping<u16>
Wrapping<u32>
Wrapping<u64>
Wrapping<usize>
}
pub trait MulAdd<MulRhs=Self, AddRhs=Self> {
type Output;
fn mul_add(self, mul: MulRhs, add: AddRhs) -> Self::Output;
}
pub fn mul_add<Output,V,M,A>(val: V, mul: M, add: A) -> Output where V: MulAdd<M,A,Output=Output> {
val.mul_add(mul, add)
}
macro_rules! impl_muladd_content {
(float, $Out:ty, $MulRhs:ty, $AddRhs:ty) => {
type Output = $Out;
fn mul_add(self, mul: $MulRhs, add: $AddRhs) -> Self::Output {
self * mul + add
}
};
(integer, $Out:ty, $MulRhs:ty, $AddRhs:ty) => {
type Output = $Out;
fn mul_add(self, mul: $MulRhs, add: $AddRhs) -> Self::Output {
self * mul + add
}
};
}
macro_rules! impl_muladd {
($kind:ident $($ty:ty)+) => {
$(
impl MulAdd< $ty, $ty> for $ty { impl_muladd_content!{$kind, $ty, $ty, $ty} }
impl< 'c> MulAdd< $ty, &'c $ty> for $ty { impl_muladd_content!{$kind, $ty, $ty, &'c $ty} }
impl< 'b > MulAdd<&'b $ty, $ty> for $ty { impl_muladd_content!{$kind, $ty, &'b $ty, $ty} }
impl< 'b, 'c> MulAdd<&'b $ty, &'c $ty> for $ty { impl_muladd_content!{$kind, $ty, &'b $ty, &'c $ty} }
impl<'a, > MulAdd< $ty, $ty> for &'a $ty { impl_muladd_content!{$kind, $ty, $ty, $ty} }
impl<'a, 'c> MulAdd< $ty, &'c $ty> for &'a $ty { impl_muladd_content!{$kind, $ty, $ty, &'c $ty} }
impl<'a, 'b, > MulAdd<&'b $ty, $ty> for &'a $ty { impl_muladd_content!{$kind, $ty, &'b $ty, $ty} }
impl<'a, 'b, 'c> MulAdd<&'b $ty, &'c $ty> for &'a $ty { impl_muladd_content!{$kind, $ty, &'b $ty, &'c $ty} }
)+
}
}
impl_muladd!{float f32 f64}
impl_muladd!{integer
i8 i16 i32 i64 isize u8 u16 u32 u64 usize
Wrapping<i8>
Wrapping<i16>
Wrapping<i32>
Wrapping<i64>
Wrapping<isize>
Wrapping<u8>
Wrapping<u16>
Wrapping<u32>
Wrapping<u64>
Wrapping<usize>
}
pub trait Lerp<Factor=f32>: Sized
{
fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> Self;
fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> Self;
fn lerp_precise(from: Self, to: Self, factor: Factor) -> Self where Factor: Clamp + Zero + One
{
Self::lerp_unclamped_precise(from, to, factor.clamped01())
}
fn lerp(from: Self, to: Self, factor: Factor) -> Self where Factor: Clamp + Zero + One
{
Self::lerp_unclamped(from, to, factor.clamped01())
}
}
macro_rules! lerp_impl_float {
($($T:ty)+) => {
$(
impl Lerp<$T> for $T {
fn lerp_unclamped_precise(from: Self, to: Self, factor: Self) -> Self {
from*(Self::one()-factor) + to*factor
}
fn lerp_unclamped(from: Self, to: Self, factor: Self) -> Self {
factor.mul_add(to - from, from)
}
}
)+
}
}
macro_rules! lerp_impl_integer {
($($T:ty)+) => {
$(
impl Lerp<f32> for $T {
fn lerp_unclamped_precise(from: Self, to: Self, factor: f32) -> Self {
((from as f32)*((1f32)-factor) + (to as f32)*factor).round() as Self
}
fn lerp_unclamped(from: Self, to: Self, factor: f32) -> Self {
factor.mul_add((to - from) as f32, from as f32).round() as Self
}
}
impl Lerp<f64> for $T {
fn lerp_unclamped_precise(from: Self, to: Self, factor: f64) -> Self {
((from as f64)*((1f64)-factor) + (to as f64)*factor).round() as Self
}
fn lerp_unclamped(from: Self, to: Self, factor: f64) -> Self {
factor.mul_add((to - from) as f64, from as f64).round() as Self
}
}
)+
}
}
lerp_impl_float!{f32 f64}
lerp_impl_integer!{
i8 i16 i32 i64 isize u8 u16 u32 u64 usize
}
pub trait Wrap<Bound=Self>: Sized {
fn wrapped(self, upper: Bound) -> Self;
fn wrap(val: Self, upper: Bound) -> Self {
val.wrapped(upper)
}
fn wrapped_2pi(self) -> Self where Bound: FloatConst + Add<Output=Bound> {
self.wrapped(Bound::PI() + Bound::PI())
}
fn wrap_2pi(val: Self) -> Self where Bound: FloatConst + Add<Output=Bound> {
val.wrapped_2pi()
}
fn wrapped_between(self, lower: Bound, upper: Bound) -> Self
where Self: Sub<Output=Self> + Add<Output=Self> + From<Bound>,
Bound: Copy + Sub<Output=Bound>
{
let out = self - Self::from(lower);
let out = out.wrapped(upper - lower);
out + Self::from(lower)
}
fn wrap_between(val: Self, lower: Bound, upper: Bound) -> Self
where Self: Sub<Output=Self> + Add<Output=Self> + From<Bound>,
Bound: Copy + Sub<Output=Bound>
{
val.wrapped_between(lower, upper)
}
fn pingpong(self, upper: Bound) -> Self
where Self: Signed + From<Bound> + Sub<Output=Self>,
Bound: Add<Output=Bound> + Copy
{
let t = self.wrapped(upper + upper);
let upper = || Self::from(upper);
upper() - (t - upper()).abs()
}
fn delta_angle(self, target: Self) -> Self
where Self: From<Bound> + Sub<Output=Self> + PartialOrd,
Bound: FloatConst + Add<Output=Bound>
{
let num = Self::wrap(target - self, Bound::PI() + Bound::PI());
if num > Self::from(Bound::PI()) {
return num - Self::from(Bound::PI() + Bound::PI());
}
num
}
fn delta_angle_degrees(self, target: Self) -> Self
where Self: From<Bound> + Sub<Output=Self> + PartialOrd,
Bound: From<u16>
{
let num = Self::wrap(target - self, Bound::from(360));
if num > Self::from(Bound::from(180)) {
return num - Self::from(Bound::from(360));
}
num
}
}
macro_rules! wrap_impl_float {
($($T:ty)+) => {
$(
impl Wrap for $T {
fn wrapped(self, upper: Self) -> Self {
self - (self/upper).floor() * upper
}
}
)+
}
}
macro_rules! wrap_impl_integer {
($($T:ty)+) => {
$(
impl Wrap for $T {
fn wrapped(self, upper: Self) -> Self {
self - (self/upper) * upper
}
}
)+
}
}
wrap_impl_float!{f32 f64}
wrap_impl_integer!{
i8 i16 i32 i64 isize u8 u16 u32 u64 usize
Wrapping<i8>
Wrapping<i16>
Wrapping<i32>
Wrapping<i64>
Wrapping<isize>
Wrapping<u8>
Wrapping<u16>
Wrapping<u32>
Wrapping<u64>
Wrapping<usize>
}
pub trait ColorComponent : Zero {
fn full() -> Self;
}
impl ColorComponent for f32 { fn full() -> Self { 1f32 } }
impl ColorComponent for f64 { fn full() -> Self { 1f64 } }
impl ColorComponent for u8 { fn full() -> Self { ::core::u8 ::MAX } }
impl ColorComponent for u16 { fn full() -> Self { ::core::u16 ::MAX } }
impl ColorComponent for u32 { fn full() -> Self { ::core::u32 ::MAX } }
impl ColorComponent for u64 { fn full() -> Self { ::core::u64 ::MAX } }
impl ColorComponent for i8 { fn full() -> Self { ::core::i8 ::MAX } }
impl ColorComponent for i16 { fn full() -> Self { ::core::i16 ::MAX } }
impl ColorComponent for i32 { fn full() -> Self { ::core::i32 ::MAX } }
impl ColorComponent for i64 { fn full() -> Self { ::core::i64 ::MAX } }
impl ColorComponent for Wrapping<u8 > { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<u16> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<u32> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<u64> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<i8 > { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<i16> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<i32> { fn full() -> Self { Wrapping(ColorComponent::full()) } }
impl ColorComponent for Wrapping<i64> { fn full() -> Self { Wrapping(ColorComponent::full()) } }