use std::str::FromStr;
pub mod format;
use crate::Value;
#[derive(Debug, Clone, Copy)]
pub enum Number {
I64(i64),
U64(u64),
I128(i128),
U128(u128),
F64(f64),
}
impl PartialEq for Number {
fn eq(&self, other: &Self) -> bool {
match self.ordered_tuple(other) {
(Number::I64(i1), Number::I64(i2)) => i1 == i2,
(Number::U64(u1), Number::I64(i2)) if *i2 >= 0 => *u1 == *i2 as u64,
(Number::U64(u1), Number::U64(u2)) => u1 == u2,
(Number::I128(i1), Number::I64(i2)) => *i1 == *i2 as i128,
(Number::I128(i1), Number::U64(u2)) => *i1 == *u2 as i128,
(Number::I128(i1), Number::I128(i2)) => i1 == i2,
(Number::U128(u1), Number::I64(i2)) if *i2 >= 0 => *u1 == *i2 as u128,
(Number::U128(u1), Number::U64(u2)) => *u1 == *u2 as u128,
(Number::U128(u1), Number::I128(i2)) if *i2 >= 0 => *u1 == *i2 as u128,
(Number::U128(u1), Number::U128(u2)) => u1 == u2,
(Number::F64(f1), n2) => f64::abs(f1 - n2.as_f64()) < f64::EPSILON,
_ => false,
}
}
}
impl Number {
fn ord(&self) -> usize {
match self {
Number::I64(_) => 0,
Number::U64(_) => 1,
Number::I128(_) => 2,
Number::U128(_) => 3,
Number::F64(_) => 4,
}
}
fn ordered_tuple<'a>(&'a self, other: &'a Self) -> (&'a Self, &'a Self) {
if self.ord() > other.ord() {
(self, other)
} else {
(other, self)
}
}
pub fn as_f64(&self) -> f64 {
match self {
Number::I64(v) => *v as f64,
Number::U64(v) => *v as f64,
Number::I128(v) => *v as f64,
Number::U128(v) => *v as f64,
Number::F64(v) => *v,
}
}
pub fn as_string(&self) -> String {
match self {
Number::I64(n) => n.to_string(),
Number::U64(n) => n.to_string(),
Number::I128(n) => n.to_string(),
Number::U128(n) => n.to_string(),
Number::F64(n) => n.to_string(),
}
}
}
impl FromStr for Number {
type Err = std::num::ParseFloatError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.contains('.') {
match s.parse::<f64>() {
Ok(f) => Ok(Number::F64(f)),
Err(e) => Err(e),
}
} else {
if let Ok(i) = s.parse::<i64>() {
Ok(Number::I64(i))
} else if let Ok(u) = s.parse::<u64>() {
Ok(Number::U64(u))
} else if let Ok(i) = s.parse::<i128>() {
Ok(Number::I128(i))
} else if let Ok(u) = s.parse::<u128>() {
Ok(Number::U128(u))
} else {
match s.parse::<f64>() {
Ok(f) => Ok(Number::F64(f)),
Err(e) => Err(e),
}
}
}
}
}
impl<'a> From<Number> for Value<'a> {
fn from(value: Number) -> Self {
Self::Number {
value,
format: None,
}
}
}
macro_rules! impl_from_for_number {
($($t:ty => $variant:ident),*) => {
$(
impl From<$t> for Number {
fn from(value: $t) -> Self {
Number::$variant(value as _)
}
}
impl From<&$t> for Number {
fn from(value: &$t) -> Self {
Number::$variant(*value as _)
}
}
impl From<$t> for Value<'_> {
fn from(value: $t) -> Self {
Value::Number {
value: Number::$variant(value as _),
format: None
}
}
}
impl From<&$t> for Value<'_> {
fn from(value: &$t) -> Self {
Value::Number{
value: Number::$variant(*value as _),
format: None
}
}
}
)*
};
}
impl_from_for_number! {
i8 => I64,
i16 => I64,
i32 => I64,
i64 => I64,
i128 => I128,
isize => I64,
u8 => U64,
u16 => U64,
u32 => U64,
u64 => U64,
u128 => U128,
usize => U64,
f32 => F64,
f64 => F64
}
#[cfg(test)]
mod test {
use super::Number;
#[test]
fn test_number_equality() {
let n1 = Number::I64(0);
let n2 = Number::F64(0f64);
assert_eq!(n1, n2);
}
}