use std::ops::Mul;
use std::ops::MulAssign;
use std::ops::Add;
use std::ops::AddAssign;
use std::ops::Sub;
use std::ops::SubAssign;
use std::ops::Div;
use std::ops::DivAssign;
use std::ops::Rem;
use std::ops::RemAssign;
use std::ops::Neg;
use std::ops::Shl;
use std::ops::ShlAssign;
use std::ops::Shr;
use std::ops::ShrAssign;
use std::ops::BitOr;
use std::ops::BitOrAssign;
use std::ops::BitAnd;
use std::ops::BitAndAssign;
use std::ops::BitXor;
use std::ops::BitXorAssign;
use std::cmp::PartialEq;
use std::cmp::PartialOrd;
use std::fmt::Display;
pub trait Base<T: Number>:
Copy + Display +
Add<Output=Self> + AddAssign +
Sub<Output=Self> + SubAssign +
Mul<Output=Self> + MulAssign +
Div<Output=Self> + DivAssign +
Rem<Output=Self> + RemAssign
where Self: Sized {
fn zero() -> Self;
fn one() -> Self;
fn two() -> Self;
fn three() -> Self;
fn four() -> Self;
fn min_value() -> Self;
fn max_value() -> Self;
}
pub trait NumberOps<T: Number> {
fn min(a: Self, b: Self) -> Self;
fn max(a: Self, b: Self) -> Self;
fn clamp(x: Self, min: Self, max: Self) -> Self;
fn step(a: Self, b: Self) -> Self;
}
pub trait SignedNumberOps<T: SignedNumber>: Neg<Output=Self> {
fn signum(a: Self) -> Self;
fn abs(a: Self) -> Self;
}
pub trait IntegerOps<T: Integer> {
fn pow(a: Self, exp: u32) -> Self;
}
pub trait Lerp<T: Float> {
fn lerp(e0: Self, e1: Self, t: T) -> Self;
}
pub trait Cast<T: Number> where Self: Sized {
fn from_f32(v: f32) -> Self;
fn from_f64(v: f64) -> Self;
fn from_u32(v: u32) -> Self;
fn from_i32(v: i32) -> Self;
fn from_u64(v: u64) -> Self;
fn from_i64(v: i64) -> Self;
fn from_usize(v: usize) -> Self;
fn as_f32(&self) -> f32;
fn as_f64(&self) -> f64;
fn as_u32(&self) -> u32;
fn as_i32(&self) -> i32;
fn as_u64(&self) -> u64;
fn as_i64(&self) -> i64;
fn as_usize(&self) -> usize;
}
pub trait FloatOps<T: Float>: Lerp<T> where Self: Sized {
fn point_five() -> Self;
fn pi() -> Self;
fn two_pi() -> Self;
fn inv_pi() -> Self;
fn phi() -> Self;
fn inv_phi() -> Self;
fn tau() -> Self;
fn sqrt(a: Self) -> Self;
fn rsqrt(a: Self) -> Self;
fn recip(a: Self) -> Self;
fn powi(a: Self, exp: i32) -> Self;
fn powf(a: Self, exp: T) -> Self;
fn mad(m: Self, a: Self, b: Self) -> Self;
fn approx(a: Self, b: Self, eps: T) -> bool;
fn floor(a: Self) -> Self;
fn ceil(a: Self) -> Self;
fn copysign(a: Self, sign: T) -> Self;
fn smoothstep(e0: Self, e1: Self, t: T) -> Self;
fn round(a: Self) -> Self;
fn is_nan(a: Self) -> Self;
fn is_infinite(a: Self) -> Self;
fn is_finite(a: Self) -> Self;
fn saturate(x: Self) -> Self;
fn deg_to_rad(theta: Self) -> Self;
fn rad_to_deg(theta: Self) -> Self;
fn fmod(x: Self, y: Self) -> Self;
fn frac(v: Self) -> Self;
fn trunc(v: Self) -> Self;
fn modf(v: Self) -> (Self, Self);
fn cos(v: Self) -> Self;
fn sin(v: Self) -> Self;
fn tan(v: Self) -> Self;
fn acos(v: Self) -> Self;
fn asin(v: Self) -> Self;
fn atan(v: Self) -> Self;
fn cosh(v: Self) -> Self;
fn sinh(v: Self) -> Self;
fn tanh(v: Self) -> Self;
fn sin_cos(v: Self) -> (Self, Self);
fn atan2(y: Self, x: Self) -> Self;
fn exp(v: Self) -> Self;
fn exp2(v: Self) -> Self;
fn log2(v: Self) -> Self;
fn log10(v: Self) -> Self;
fn log(v: Self, base: T) -> Self;
}
macro_rules! number_trait_impl {
($($func:ident),*) => {
pub trait Number: Base<Self> + Default + PartialEq + PartialOrd {}
number_impl!(f64 { $($func),* }, 0.0, 1.0);
number_impl!(f32 { $($func),* }, 0.0, 1.0);
number_impl!(usize { $($func),* }, 0, 1);
number_impl!(isize { $($func),* }, 0, 1);
number_impl!(i64 { $($func),* }, 0, 1);
number_impl!(u64 { $($func),* }, 0, 1);
number_impl!(i32 { $($func),* }, 0, 1);
number_impl!(u32 { $($func),* }, 0, 1);
number_impl!(i16 { $($func),* }, 0, 1);
number_impl!(u16 { $($func),* }, 0, 1);
number_impl!(i8 { $($func),* }, 0, 1);
number_impl!(u8 { $($func),* }, 0, 1);
}
}
macro_rules! number_impl {
($t:ident { $($func:ident),* }, $zero:literal, $one:literal) => {
impl Base<$t> for $t {
fn min_value() -> Self {
$t::MIN
}
fn max_value() -> Self {
$t::MAX
}
fn zero() -> Self {
$zero
}
fn one() -> Self {
$one
}
fn two() -> Self {
2 as Self
}
fn three() -> Self {
3 as Self
}
fn four() -> Self {
4 as Self
}
}
impl Number for $t {}
impl NumberOps<$t> for $t {
fn min(a: Self, b: Self) -> Self {
a.min(b)
}
fn max(a: Self, b: Self) -> Self {
a.max(b)
}
fn clamp(x: Self, min: Self, max: Self) -> Self {
NumberOps::max(NumberOps::min(x, max), min)
}
fn step(a: Self, b: Self) -> Self {
if a >= b {
Self::one()
}
else {
Self::zero()
}
}
}
impl Cast<$t> for $t {
fn from_f32(v: f32) -> Self {
v as Self
}
fn from_f64(v: f64) -> Self {
v as Self
}
fn from_u32(v: u32) -> Self {
v as Self
}
fn from_i32(v: i32) -> Self {
v as Self
}
fn from_u64(v: u64) -> Self {
v as Self
}
fn from_i64(v: i64) -> Self {
v as Self
}
fn from_usize(v: usize) -> Self {
v as Self
}
fn as_f32(&self) -> f32 {
*self as f32
}
fn as_f64(&self) -> f64 {
*self as f64
}
fn as_u32(&self) -> u32 {
*self as u32
}
fn as_i32(&self) -> i32 {
*self as i32
}
fn as_u64(&self) -> u64 {
*self as u64
}
fn as_i64(&self) -> i64 {
*self as i64
}
fn as_usize(&self) -> usize {
*self as usize
}
}
}
}
macro_rules! signed_number_trait_impl {
($($func:ident),*) => {
pub trait SignedNumber: Number + Neg<Output=Self> {
fn minus_one() -> Self;
}
signed_number_impl!(f64 { $($func),* }, -1.0);
signed_number_impl!(f32 { $($func),* }, -1.0);
signed_number_impl!(isize { $($func),* }, -1);
signed_number_impl!(i64 { $($func),* }, -1);
signed_number_impl!(i32 { $($func),* }, -1);
signed_number_impl!(i16 { $($func),* }, -1);
signed_number_impl!(i8 { $($func),* }, -1);
}
}
macro_rules! signed_number_impl {
($t:ident { $($func:ident),* }, $minus_one:literal) => {
impl SignedNumber for $t {
fn minus_one() -> Self {
$minus_one
}
}
impl SignedNumberOps<$t> for $t {
$(
fn $func(v: Self) -> Self {
v.$func()
}
)*
}
}
}
macro_rules! float_trait_impl {
($($func:ident),*) => {
pub trait Float: SignedNumber {
fn small_epsilon() -> Self;
}
float_impl!(f64 { $($func),* });
float_impl!(f32 { $($func),* });
}
}
macro_rules! float_impl {
($t:ident { $($func:ident),* } ) => {
impl Float for $t {
fn small_epsilon() -> Self {
1e-30
}
}
impl Lerp<$t> for $t {
fn lerp(e0: Self, e1: Self, t: Self) -> Self {
e0 + t * (e1 - e0)
}
}
impl FloatOps<$t> for $t {
$(
fn $func(v: Self) -> Self {
v.$func()
}
)*
fn point_five() -> Self {
0.5 as Self
}
#[allow(clippy::excessive_precision)]
fn pi() -> Self {
3.14159265358979323846264338327950288 as Self
}
fn two_pi() -> Self {
2.0 as Self * Self::pi() as Self
}
fn inv_pi() -> Self {
1.0 as Self / Self::pi() as Self
}
#[allow(clippy::excessive_precision)]
fn phi() -> Self {
1.618033988749894 as Self
}
fn inv_phi() -> Self {
1.0 as Self / Self::phi() as Self
}
#[allow(clippy::excessive_precision)]
fn tau() -> Self {
6.2831853071795864 as Self
}
fn rsqrt(a: Self) -> Self {
Self::one()/Self::sqrt(a)
}
fn approx(a: Self, b: Self, eps: Self) -> bool {
Self::abs(a - b) < eps
}
fn mad(m: Self, a: Self, b: Self) -> Self {
m.mul_add(a, b)
}
fn is_nan(v: Self) -> $t {
if v.is_nan() { $t::one() } else { $t::zero() }
}
fn is_infinite(v: Self) -> $t {
if v.is_infinite() { $t::one() } else { $t::zero() }
}
fn is_finite(v: Self) -> $t {
if v.is_finite() { $t::one() } else { $t::zero() }
}
fn copysign(a: Self, sign: $t) -> Self {
a.copysign(sign)
}
fn smoothstep(e0: Self, e1: Self, t: Self) -> Self {
if t < e0 { return Self::zero(); }
if (t >= e1) { return Self::one(); }
let x = (t - e0) / (e1 - e0);
x * x * (3 as Self - 2 as Self * x)
}
fn saturate(v: Self) -> Self {
Self::max(Self::min(v, 1.0), 0.0)
}
fn powi(v: Self, exp: i32) -> Self {
v.powi(exp)
}
fn powf(v: Self, exp: $t) -> Self {
v.powf(exp)
}
fn fmod(x: Self, y: Self) -> Self {
x % y
}
fn frac(v: Self) -> Self {
v.fract()
}
fn trunc(v: Self) -> Self {
v.trunc()
}
fn modf(v: Self) -> (Self, Self) {
(Self::frac(v), Self::trunc(v))
}
fn log(v: Self, base: Self) -> Self {
v.log(base)
}
fn sin_cos(v: Self) -> (Self, Self) {
(v.sin(), v.cos())
}
fn atan2(y: Self, x: Self) -> Self {
y.atan2(x)
}
fn deg_to_rad(theta: Self) -> Self {
theta.to_radians()
}
fn rad_to_deg(theta: Self) -> Self {
theta.to_degrees()
}
}
}
}
macro_rules! integer_trait_impl {
($($func:ident),*) => {
pub trait Integer: Number +
Shl<Output=Self> + ShlAssign +
Shr<Output=Self> + ShrAssign +
BitOr<Output=Self> + BitOrAssign +
BitAnd<Output=Self> + BitAndAssign +
BitXor<Output=Self> + BitXorAssign {
}
integer_impl!(i8 { $($func),* });
integer_impl!(u8 { $($func),* });
integer_impl!(i16 { $($func),* });
integer_impl!(u16 { $($func),* });
integer_impl!(i32 { $($func),* });
integer_impl!(u32 { $($func),* });
integer_impl!(i64 { $($func),* });
integer_impl!(u64 { $($func),* });
}
}
macro_rules! integer_impl {
($t:ident { $($func:ident),* } ) => {
impl Integer for $t {
}
impl IntegerOps<$t> for $t {
fn pow(v: Self, exp: u32) -> Self {
v.pow(exp)
}
}
}
}
number_trait_impl!();
integer_trait_impl!();
signed_number_trait_impl!(signum, abs);
float_trait_impl!(
floor, ceil, round, sqrt, recip,
cos, sin, tan, acos, asin, atan, cosh, sinh, tanh,
exp, exp2, log2, log10
);