use std::fmt::{Debug, Display};
use std::i64;
use std::ops::RangeInclusive;
use std::str::FromStr;
use rand::{Rng, distributions::Uniform};
use crate::core::types::ArrayElement;
pub trait Numeric: ArrayElement + Clone + Copy + Display + Debug + PartialEq + PartialOrd + FromStr {
fn rand(range: RangeInclusive<Self>) -> Self;
fn from<U: Numeric>(value: U) -> Self {
Self::from_f64(value.to_f64())
}
fn from_usize(value: usize) -> Self;
fn from_f64(value: f64) -> Self;
fn to_usize(&self) -> usize;
fn to_isize(&self) -> isize;
fn to_i32(&self) -> i32;
fn to_f64(&self) -> f64;
fn is_inf(&self) -> bool;
#[must_use]
fn max(&self) -> Self;
#[must_use]
fn bitwise_and(&self, other: &Self) -> Self;
#[must_use]
fn bitwise_or(&self, other: &Self) -> Self;
#[must_use]
fn bitwise_xor(&self, other: &Self) -> Self;
#[must_use]
fn bitwise_not(&self) -> Self;
#[must_use]
fn left_shift(&self, other: &Self) -> Self;
#[must_use]
fn right_shift(&self, other: &Self) -> Self;
fn binary_repr(&self) -> String;
}
macro_rules! impl_numeric {
($t:ty) => {
impl ArrayElement for $t {
fn zero() -> Self {
0 as $t
}
fn one() -> Self {
1 as $t
}
fn is_nan(&self) -> bool {
false
}
}
impl Numeric for $t {
fn rand(range: RangeInclusive<Self>) -> $t {
let mut rng = rand::thread_rng();
let value = rng.sample(&Uniform::from(range));
value as $t
}
fn from_usize(value: usize) -> $t {
value as $t
}
fn from_f64(value: f64) -> $t {
value as $t
}
fn to_usize(&self) -> usize {
*self as usize
}
fn to_isize(&self) -> isize {
*self as isize
}
fn to_i32(&self) -> i32 {
*self as i32
}
fn to_f64(&self) -> f64 {
*self as f64
}
fn is_inf(&self) -> bool {
false
}
fn max(&self) -> Self {
<$t>::MAX
}
fn bitwise_and(&self, other: &Self) -> Self {
self & other
}
fn bitwise_or(&self, other: &Self) -> Self {
self | other
}
fn bitwise_xor(&self, other: &Self) -> Self {
self ^ other
}
fn bitwise_not(&self) -> Self {
!self.clone()
}
fn left_shift(&self, other: &Self) -> Self {
self << other
}
fn right_shift(&self, other: &Self) -> Self {
self >> other
}
fn binary_repr(&self) -> String {
format!("{self:b}")
}
}
};
}
impl_numeric!(isize);
impl_numeric!(i8);
impl_numeric!(i16);
impl_numeric!(i32);
impl_numeric!(i64);
impl_numeric!(usize);
impl_numeric!(u8);
impl_numeric!(u16);
impl_numeric!(u32);
impl_numeric!(u64);
macro_rules! impl_numeric_float {
($t:ty, $ti:ty) => {
impl ArrayElement for $t {
fn zero() -> Self {
0 as $t
}
fn one() -> Self {
1 as $t
}
fn is_nan(&self) -> bool {
<$t>::is_nan(*self)
}
}
impl Numeric for $t {
fn rand(range: RangeInclusive<Self>) -> $t {
let mut rng = rand::thread_rng();
let value = rng.sample(&Uniform::from(range));
value as $t
}
fn from_usize(value: usize) -> $t {
value as $t
}
fn from_f64(value: f64) -> $t {
value as $t
}
fn to_usize(&self) -> usize {
*self as usize
}
fn to_isize(&self) -> isize {
*self as isize
}
fn to_i32(&self) -> i32 {
*self as i32
}
fn to_f64(&self) -> f64 {
*self as f64
}
fn is_inf(&self) -> bool {
<$t>::is_infinite(*self)
}
fn max(&self) -> Self {
<$t>::MAX
}
fn bitwise_and(&self, other: &Self) -> Self {
(*self as $ti & *other as $ti) as $t
}
fn bitwise_or(&self, other: &Self) -> Self {
(*self as $ti | *other as $ti) as $t
}
fn bitwise_xor(&self, other: &Self) -> Self {
(*self as $ti ^ *other as $ti) as $t
}
fn bitwise_not(&self) -> Self {
!(*self as $ti) as $t
}
fn left_shift(&self, other: &Self) -> Self {
((*self as $ti) << (*other as $ti)) as $t
}
fn right_shift(&self, other: &Self) -> Self {
((*self as $ti) >> (*other as $ti)) as $t
}
fn binary_repr(&self) -> String {
format!("{:b}", *self as $ti)
}
}
};
}
impl_numeric_float!(f32, i64);
impl_numeric_float!(f64, i128);