Files
iris/src/util/math.rs

88 lines
2.5 KiB
Rust

use std::ops::*;
pub const trait LerpUtil {
fn lerp(self, from: Self, to: Self) -> Self;
fn lerp_inv(self, from: Self, to: Self) -> Self;
}
pub const trait DivOr {
fn div_or(self, rhs: Self, other: Self) -> Self;
}
impl const DivOr for f32 {
fn div_or(self, rhs: Self, other: Self) -> Self {
let res = self / rhs;
if res.is_nan() { other } else { res }
}
}
impl<T: const Add<Output = T> + const Sub<Output = T> + const Mul<Output = T> + const DivOr + Copy> const
LerpUtil for T
{
/// linear interpolation
/// from * (1.0 - self) + to * self
fn lerp(self, from: Self, to: Self) -> Self {
from + (to - from) * self
}
/// inverse of lerp
fn lerp_inv(self, from: Self, to: Self) -> Self {
(self - from).div_or(to - from, from)
}
}
macro_rules! impl_op {
($T:ident $op:ident $fn:ident $opa:ident $fna:ident; $($field:ident)*) => {
#[allow(non_snake_case)]
mod ${concat($T, _op_, $fn, _impl)} {
use super::*;
#[allow(unused_imports)]
use std::ops::*;
impl const $op for $T {
type Output = Self;
fn $fn(self, rhs: Self) -> Self::Output {
Self {
$($field: self.$field.$fn(rhs.$field),)*
}
}
}
impl const $opa for $T {
fn $fna(&mut self, rhs: Self) {
*self = self.$fn(rhs);
}
}
impl const $op<f32> for $T {
type Output = Self;
fn $fn(self, rhs: f32) -> Self::Output {
Self {
$($field: self.$field.$fn(rhs),)*
}
}
}
impl const $op<$T> for f32 {
type Output = $T;
fn $fn(self, rhs: $T) -> Self::Output {
$T {
$($field: self.$fn(rhs.$field),)*
}
}
}
impl const $opa<f32> for $T {
fn $fna(&mut self, rhs: f32) {
*self = self.$fn(rhs);
}
}
}
};
($T:ident $op:ident $fn:ident; $($field:ident)*) => {
impl_op!($T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*);
};
(impl $op:ident for $T:ident: $fn:ident $($field:ident)*) => {
impl_op!($T $op $fn ${concat($op,Assign)} ${concat($fn,_assign)}; $($field)*);
};
}
pub(crate) use impl_op;