use crate::{prelude::*, config::StackAddress};
pub(crate) type Signed = i64;
pub(crate) type Unsigned = u64;
pub(crate) type Float = f64;
#[derive(Clone, Copy)]
pub enum Numeric {
Signed(Signed),
Unsigned(Unsigned),
Float(Float),
}
impl Hash for Numeric {
fn hash<H: Hasher>(self: &Self, state: &mut H) {
match self {
Self::Signed(s) => s.hash(state),
Self::Unsigned(u) => u.hash(state),
Self::Float(f) => {
if f.is_nan() {
f64::NAN.to_ne_bytes().hash(state)
} else {
f.to_ne_bytes().hash(state)
}
},
}
}
}
impl Numeric {
pub const fn is_integer(self: &Self) -> bool {
match self {
Numeric::Signed(_) => true,
Numeric::Unsigned(_) => true,
_ => false,
}
}
pub const fn is_float(self: &Self) -> bool {
match self {
Numeric::Float(_) => true,
_ => false,
}
}
pub const fn as_unsigned(self: &Self) -> Option<StackAddress> {
match self {
&Numeric::Signed(v) if v >= 0 => Some(v as StackAddress),
&Numeric::Unsigned(v) => Some(v as StackAddress),
_ => None,
}
}
pub fn inc(self: Self) -> Self {
match self {
Self::Signed(v) => Self::Signed(v + 1),
Self::Unsigned(v) => Self::Unsigned(v + 1),
Self::Float(v) => Self::Float(v + 1.0),
}
}
}
impl PartialEq for Numeric {
fn eq(self: &Self, other: &Numeric) -> bool {
if let Some(ordering) = self.partial_cmp(other) {
ordering == Ordering::Equal
} else {
false
}
}
}
impl Eq for Numeric { }
impl PartialOrd for Numeric {
fn partial_cmp(&self, other: &Numeric) -> Option<Ordering> {
match self {
Numeric::Signed(s) => {
match other {
Numeric::Signed(o) => {
s.partial_cmp(o)
},
Numeric::Unsigned(o) => {
if *s < 0 {
Some(Ordering::Less)
} else {
(*s as Unsigned).partial_cmp(o)
}
},
_ => None,
}
},
Numeric::Unsigned(s) => {
match other {
Numeric::Signed(o) => {
if *o < 0 {
Some(Ordering::Greater)
} else {
s.partial_cmp(&(*o as Unsigned))
}
},
Numeric::Unsigned(o) => {
s.partial_cmp(o)
}
_ => None,
}
},
Numeric::Float(s) => {
match other {
Numeric::Float(o) => {
s.partial_cmp(o)
}
_ => None,
}
},
}
}
}
impl Ord for Numeric {
fn cmp(&self, other: &Numeric) -> Ordering {
self.partial_cmp(other).unwrap()
}
}
impl Debug for Numeric {
fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Numeric::Signed(v) => write!(f, "{v} (signed)"),
Numeric::Unsigned(v) => write!(f, "{v} (unsigned)"),
Numeric::Float(v) => write!(f, "{v} (float)"),
}
}
}
impl Display for Numeric {
fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Numeric::Signed(v) => write!(f, "{v}"),
Numeric::Unsigned(v) => write!(f, "{v}"),
Numeric::Float(v) => write!(f, "{v}"),
}
}
}