use core::{
fmt::Debug,
ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign},
};
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use core_maths::CoreFloat;
use super::type_lists::with_all_scalar_types;
use crate::ops::{HasScalar, One, Select, Zero};
pub trait Scalar:
Copy
+ Debug
+ HasScalar
+ Zero
+ One
+ Select
+ PartialEq
+ PartialOrd
+ ScalarCasts
+ Add<Output = Self>
+ AddAssign
+ Sub<Output = Self>
+ SubAssign
+ Mul<Output = Self>
+ MulAssign
+ Div<Output = Self>
+ DivAssign
{
const MAX: Self;
const MIN: Self;
#[inline]
fn from_scalar<T: Scalar>(value: T) -> Self
where
Self: ScalarCast<T>,
{
<Self as ScalarCast<T>>::from_scalar_impl(value)
}
#[inline]
fn as_scalar<T: Scalar>(&self) -> T
where
Self: ScalarCast<T>,
{
<Self as ScalarCast<T>>::as_scalar_impl(self)
}
}
pub trait FloatScalar:
Scalar
+ CoreFloat
+ Neg<Output = Self>
+ AbsDiffEq<Epsilon = Self>
+ RelativeEq<Epsilon = Self>
+ UlpsEq<Epsilon = Self>
{
const INFINITY: Self;
const NEG_INFINITY: Self;
const NAN: Self;
fn is_nan(self) -> bool;
fn is_finite(self) -> bool;
fn is_infinite(self) -> bool;
}
pub trait IntScalar: Scalar + Ord + Eq {}
pub trait UIntScalar: IntScalar {}
pub trait SIntScalar: IntScalar + Neg<Output = Self> {}
pub trait ScalarCast<T>: Sized {
fn from_scalar_impl(value: T) -> Self;
fn as_scalar_impl(&self) -> T;
}
macro_rules! define_scalar_casts_trait {
($($ty:ty),+ $(,)?) => {
pub trait ScalarCasts: $(ScalarCast<$ty> +)+ {}
impl<T> ScalarCasts for T where T: $(ScalarCast<$ty> +)+ {}
};
}
with_all_scalar_types!(define_scalar_casts_trait);