use core::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Not, Rem, Shl, Shr, Sub};
use num_traits::{Float, One, Zero};
use crate::basenum::{ApproxEq, BaseFloat, BaseInt, BaseNum, SignedNum};
pub trait GenNum<E: BaseNum>:
Copy
+ Sized
+ Clone
+ One
+ Zero
+ Div<Self, Output = Self>
+ Rem<Self, Output = Self>
+ Add<E, Output = Self>
+ Mul<E, Output = Self>
{
fn from_s(x: E) -> Self;
fn map<F>(self, f: F) -> Self
where
F: Fn(E) -> E;
fn zip<F>(self, y: Self, f: F) -> Self
where
F: Fn(E, E) -> E;
fn split<F>(self, f: F) -> (Self, Self)
where
F: Fn(E) -> (E, E);
fn map2<F>(self, y: Self, f: F) -> (Self, Self)
where
F: Fn(E, E) -> (E, E);
}
macro_rules! impl_GenNum_for_scalar(
($t: ty) => {
impl GenNum<$t> for $t {
#[inline(always)]
fn from_s(x: $t) -> Self {
x
}
#[inline(always)]
fn map<F: Fn($t) -> $t>(self, f: F) -> $t {
f(self)
}
#[inline(always)]
fn zip<F: Fn($t, $t) -> $t>(self, y: $t, f: F) -> $t {
f(self, y)
}
#[inline(always)]
fn split<F: Fn($t) -> ($t, $t)>(self, f: F) -> ($t, $t) {
f(self)
}
#[inline(always)]
fn map2<F: Fn($t, $t) -> ($t, $t)>(self, y: $t, f: F) -> ($t, $t) {
f(self, y)
}
}
}
);
pub trait GenInt<I: BaseInt>:
GenNum<I>
+ Eq
+ Not<Output = Self>
+ BitAnd<Output = Self>
+ BitOr<Output = Self>
+ BitXor<Output = Self>
+ Shl<usize, Output = Self>
+ Shr<usize, Output = Self>
{
}
pub trait GenIType: GenInt<i32> + SignedNum + Sub<i32, Output = Self> {}
impl_GenNum_for_scalar! { i32 }
impl GenInt<i32> for i32 {}
impl GenIType for i32 {}
pub trait GenUType: GenInt<u32> {}
impl_GenNum_for_scalar! { u32 }
impl GenInt<u32> for u32 {}
impl GenUType for u32 {}
pub trait GenFloat<F: BaseFloat>:
GenNum<F> + ApproxEq<BaseType = F> + SignedNum + Sub<F, Output = Self>
{
fn fma(&self, b: &Self, c: &Self) -> Self;
}
pub trait GenType: GenFloat<f32> {}
pub trait GenDType: GenFloat<f64> {}
macro_rules! impl_GenFloat_for_scalar(
($t: ty, $gt: path) => {
impl_GenNum_for_scalar! { $t }
impl GenFloat<$t> for $t {
fn fma(&self, b: &$t, c: &$t) -> $t {
Float::mul_add(*self, *b, *c)
}
}
impl $gt for $t {}
}
);
impl_GenFloat_for_scalar! { f32, GenType }
impl_GenFloat_for_scalar! { f64, GenDType }
pub trait GenBType: Eq {}
impl GenBType for bool {}