use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use std::cmp::Ordering;
use super::frac::Frac;
pub trait Zero: Sized + Add<Self, Output = Self> {
const ZERO: Self;
}
macro_rules! int_zero_impl {
($($t:ty)*) => ($(
impl Zero for $t {
const ZERO: Self = 0 as Self;
}
)*)
}
int_zero_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
impl Zero for Frac {
const ZERO: Frac = Frac::zero();
}
pub trait One: Sized + Mul {
const ONE: Self;
}
macro_rules! one_impl {
($($t:ty)*) => ($(
impl One for $t {
const ONE: Self = 1 as Self;
}
)*)
}
one_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }
impl One for Frac {
const ONE: Frac = Frac::one();
}
pub trait Field:
Sized
+ Copy
+ std::fmt::Debug
+ std::fmt::Display
+ PartialEq
+ Add<Self, Output = Self> + AddAssign<Self>
+ Sub<Self, Output = Self> + SubAssign<Self>
+ Zero
+ Mul<Self, Output = Self> + MulAssign<Self>
+ Div<Self, Output = Self> + DivAssign<Self>
+ One
{
fn powi32(&self, p: i32) -> Self;
}
macro_rules! field_impl {
($($t:ty)*) => ($(
impl Field for $t {
fn powi32(&self, p: i32) -> Self {
self.powi(p)
}
}
)*)
}
field_impl! { f32 f64 Frac }
pub trait EpsilonEquality {
fn epsilon_equals(&self, other: &Self) -> bool;
}
macro_rules! epsilon_equality_impl {
($($t:ty)*) => ($(
impl EpsilonEquality for $t {
fn epsilon_equals(&self, other: &Self) -> bool {
(self-other).abs() < <$t>::EPSILON
}
}
)*)
}
epsilon_equality_impl! { f32 f64 }
impl EpsilonEquality for Frac {
fn epsilon_equals(&self, other: &Self) -> bool {
self == other
}
}
pub trait StabilityCmp {
fn stability_cmp(&self, other: &Self) -> Option<Ordering>;
}
macro_rules! stability_cmp_impl {
($($t:ty)*) => ($(
impl StabilityCmp for $t {
fn stability_cmp(&self, other: &Self) -> Option<Ordering> {
self.abs().partial_cmp(&other.abs())
}
}
)*)
}
stability_cmp_impl! { f32 f64 }
impl StabilityCmp for Frac {
fn stability_cmp(&self, other: &Self) -> Option<Ordering> {
if *self == Frac::ZERO {
Some(Ordering::Less)
} else if *other == Frac::ZERO {
Some(Ordering::Greater)
} else {
(other.numer.abs()+other.denom.abs())
.partial_cmp(&(self.numer.abs()+self.denom.abs()))
}
}
}
impl PartialOrd for Frac {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Frac {
fn cmp(&self, other: &Self) -> Ordering {
(self.numer*other.denom).cmp(&(other.numer*self.denom))
}
}