use std::cmp::Ordering;
use std::convert::TryFrom;
use std::fmt::Debug;
use std::fmt::Display;
use std::fmt::Formatter;
use crate::error::Result;
use crate::Error;
use ethnum::i256;
use ethnum::U256;
use num_traits::AsPrimitive;
use num_traits::Bounded;
use ordered_float::OrderedFloat;
use serde::de;
use serde::de::Deserialize;
use serde::de::Deserializer;
use serde::de::Visitor;
use serde::ser::Serialize;
use serde::ser::Serializer;
const I128_POWERS_OF_10: [i128; 39] = [
1,
10,
100,
1000,
10000,
100000,
1000000,
10000000,
100000000,
1000000000,
10000000000,
100000000000,
1000000000000,
10000000000000,
100000000000000,
1000000000000000,
10000000000000000,
100000000000000000,
1000000000000000000,
10000000000000000000,
100000000000000000000,
1000000000000000000000,
10000000000000000000000,
100000000000000000000000,
1000000000000000000000000,
10000000000000000000000000,
100000000000000000000000000,
1000000000000000000000000000,
10000000000000000000000000000,
100000000000000000000000000000,
1000000000000000000000000000000,
10000000000000000000000000000000,
100000000000000000000000000000000,
1000000000000000000000000000000000,
10000000000000000000000000000000000,
100000000000000000000000000000000000,
1000000000000000000000000000000000000,
10000000000000000000000000000000000000,
100000000000000000000000000000000000000,
];
const LEADING_ZEROS: [&str; 38] = [
"",
"0",
"00",
"000",
"0000",
"00000",
"000000",
"0000000",
"00000000",
"000000000",
"0000000000",
"00000000000",
"000000000000",
"0000000000000",
"00000000000000",
"000000000000000",
"0000000000000000",
"00000000000000000",
"000000000000000000",
"0000000000000000000",
"00000000000000000000",
"000000000000000000000",
"0000000000000000000000",
"00000000000000000000000",
"000000000000000000000000",
"0000000000000000000000000",
"00000000000000000000000000",
"000000000000000000000000000",
"0000000000000000000000000000",
"00000000000000000000000000000",
"000000000000000000000000000000",
"0000000000000000000000000000000",
"00000000000000000000000000000000",
"000000000000000000000000000000000",
"0000000000000000000000000000000000",
"00000000000000000000000000000000000",
"000000000000000000000000000000000000",
"0000000000000000000000000000000000000",
];
const I128_SCALE: usize = 38;
static I256_DIVIDE_SCALE: std::sync::LazyLock<i256> =
std::sync::LazyLock::new(|| i256::from(100000000000000000000000000000000000000_i128));
#[derive(Debug, Clone)]
pub struct Decimal64 {
pub scale: u8,
pub value: i64,
}
impl Decimal64 {
pub fn to_float64(&self) -> f64 {
let div = 10_f64.powi(self.scale as i32);
self.value as f64 / div
}
}
#[derive(Debug, Clone)]
pub struct Decimal128 {
pub scale: u8,
pub value: i128,
}
impl Decimal128 {
pub fn to_float64(&self) -> f64 {
let div = 10_f64.powi(self.scale as i32);
self.value as f64 / div
}
}
#[derive(Debug, Clone)]
pub struct Decimal256 {
pub scale: u8,
pub value: i256,
}
impl Decimal256 {
pub fn to_float64(&self) -> f64 {
let div = 10_f64.powi(self.scale as i32);
self.value.as_f64() / div
}
}
#[derive(Debug, Clone)]
pub enum Number {
Int64(i64),
UInt64(u64),
Float64(f64),
Decimal64(Decimal64),
Decimal128(Decimal128),
Decimal256(Decimal256),
}
impl<'de> Deserialize<'de> for Number {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct NumberVisitor;
impl Visitor<'_> for NumberVisitor {
type Value = Number;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a number (int64, uint64, or float64)")
}
fn visit_i64<E>(self, v: i64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(Number::Int64(v))
}
fn visit_u64<E>(self, v: u64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(Number::UInt64(v))
}
fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
where
E: de::Error,
{
Ok(Number::Float64(v))
}
}
deserializer.deserialize_any(NumberVisitor)
}
}
impl Serialize for Number {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
Number::Int64(v) => serializer.serialize_i64(*v),
Number::UInt64(v) => serializer.serialize_u64(*v),
Number::Float64(v) => serializer.serialize_f64(*v),
#[cfg(feature = "arbitrary_precision")]
Number::Decimal64(_) | Number::Decimal128(_) | Number::Decimal256(_) => {
use serde::ser::SerializeStruct;
use std::io::Write;
const NUMBER_TOKEN: &str = "$serde_json::private::Number";
if serializer.is_human_readable() {
struct WriteAdapter<'a>(&'a mut std::io::Cursor<&'a mut [u8]>);
impl std::fmt::Write for WriteAdapter<'_> {
fn write_str(&mut self, s: &str) -> std::fmt::Result {
self.0.write_all(s.as_bytes()).map_err(|_| std::fmt::Error)
}
}
impl WriteAdapter<'_> {
fn position(&self) -> usize {
self.0.position() as usize
}
}
let mut buffer = [0u8; 128];
let mut cursor = std::io::Cursor::new(&mut buffer[..]);
let mut adapter = WriteAdapter(&mut cursor);
match self {
Number::Decimal64(v) => {
format_decimal_i128(&mut adapter, v.value as i128, v.scale as usize)
.map_err(|e| {
serde::ser::Error::custom(format!(
"Format decimal64 error: {e}"
))
})?;
}
Number::Decimal128(v) => {
format_decimal_i128(&mut adapter, v.value, v.scale as usize).map_err(
|e| {
serde::ser::Error::custom(format!(
"Format decimal128 error: {e}"
))
},
)?;
}
Number::Decimal256(v) => {
format_decimal_i256(&mut adapter, v.value, v.scale as usize).map_err(
|e| {
serde::ser::Error::custom(format!(
"Format decimal256 error: {e}"
))
},
)?;
}
_ => unreachable!(),
}
let pos = adapter.position();
let num_str = std::str::from_utf8(&buffer[..pos]).map_err(|e| {
serde::ser::Error::custom(format!("Invalid decimal number: {e}"))
})?;
let mut serialize_struct = serializer.serialize_struct(NUMBER_TOKEN, 1)?;
serialize_struct.serialize_field(NUMBER_TOKEN, num_str)?;
serialize_struct.end()
} else {
use crate::constants::NUMBER_STRUCT_FIELD_HIGH_VALUE;
use crate::constants::NUMBER_STRUCT_FIELD_LOW_VALUE;
use crate::constants::NUMBER_STRUCT_FIELD_SCALE;
use crate::constants::NUMBER_STRUCT_FIELD_VALUE;
use crate::constants::NUMBER_STRUCT_TOKEN;
let mut serialize_struct =
serializer.serialize_struct(NUMBER_STRUCT_TOKEN, 2)?;
match self {
Number::Decimal64(v) => {
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_SCALE, &v.scale)?;
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_VALUE, &v.value)?;
}
Number::Decimal128(v) => {
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_SCALE, &v.scale)?;
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_VALUE, &v.value)?;
}
Number::Decimal256(v) => {
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_SCALE, &v.scale)?;
let (high_value, low_value) = v.value.into_words();
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_HIGH_VALUE, &high_value)?;
serialize_struct
.serialize_field(NUMBER_STRUCT_FIELD_LOW_VALUE, &low_value)?;
}
_ => unreachable!(),
}
serialize_struct.end()
}
}
#[cfg(not(feature = "arbitrary_precision"))]
Number::Decimal64(_) | Number::Decimal128(_) | Number::Decimal256(_) => {
let (value, scale) = match self {
Number::Decimal64(v) => (v.value as f64, v.scale as i32),
Number::Decimal128(v) => (v.value as f64, v.scale as i32),
Number::Decimal256(v) => (v.value.as_f64(), v.scale as i32),
_ => unreachable!(),
};
let scaled_value = value / 10f64.powi(scale);
serializer.serialize_f64(scaled_value)
}
}
}
}
impl Number {
pub fn as_i128(&self) -> Option<i128> {
match self {
Number::Int64(v) => Some(*v as i128),
Number::UInt64(v) => Some(*v as i128),
Number::Float64(v) => exact_float_to_int(*v),
Number::Decimal64(v) => exact_decimal_i128(v.value as i128, v.scale),
Number::Decimal128(v) => exact_decimal_i128(v.value, v.scale),
Number::Decimal256(v) => {
exact_decimal_i256(v.value, v.scale).and_then(|value| i128::try_from(value).ok())
}
}
}
pub fn as_i64(&self) -> Option<i64> {
match self {
Number::Int64(v) => Some(*v),
Number::UInt64(v) => {
if *v <= i64::MAX as u64 {
Some(*v as i64)
} else {
None
}
}
Number::Float64(v) => exact_float_to_int(*v),
Number::Decimal64(v) => exact_decimal_i128(v.value as i128, v.scale)
.and_then(|value| i64::try_from(value).ok()),
Number::Decimal128(v) => {
exact_decimal_i128(v.value, v.scale).and_then(|value| i64::try_from(value).ok())
}
Number::Decimal256(v) => {
exact_decimal_i256(v.value, v.scale).and_then(|value| i64::try_from(value).ok())
}
}
}
pub fn as_u64(&self) -> Option<u64> {
match self {
Number::Int64(v) => {
if *v >= 0 {
Some(*v as u64)
} else {
None
}
}
Number::UInt64(v) => Some(*v),
Number::Float64(v) => exact_float_to_int(*v),
Number::Decimal64(v) => exact_decimal_i128(v.value as i128, v.scale)
.and_then(|value| u64::try_from(value).ok()),
Number::Decimal128(v) => {
exact_decimal_i128(v.value, v.scale).and_then(|value| u64::try_from(value).ok())
}
Number::Decimal256(v) => {
exact_decimal_i256(v.value, v.scale).and_then(|value| u64::try_from(value).ok())
}
}
}
pub fn to_i128(&self) -> Option<i128> {
match self {
Number::Int64(v) => Some(*v as i128),
Number::UInt64(v) => Some(*v as i128),
Number::Float64(v) => round_float_to_int(*v),
Number::Decimal64(v) => round_decimal_i128(v.value as i128, v.scale),
Number::Decimal128(v) => round_decimal_i128(v.value, v.scale),
Number::Decimal256(v) => {
round_decimal_i256(v.value, v.scale).and_then(|value| i128::try_from(value).ok())
}
}
}
pub fn to_i64(&self) -> Option<i64> {
self.to_i128().and_then(|value| i64::try_from(value).ok())
}
pub fn to_u64(&self) -> Option<u64> {
self.to_i128().and_then(|value| u64::try_from(value).ok())
}
pub fn as_f64(&self) -> f64 {
match self {
Number::Int64(v) => *v as f64,
Number::UInt64(v) => *v as f64,
Number::Float64(v) => *v,
Number::Decimal64(v) => v.to_float64(),
Number::Decimal128(v) => v.to_float64(),
Number::Decimal256(v) => v.to_float64(),
}
}
pub fn neg(&self) -> Result<Number> {
match self {
Number::Int64(v) => v
.checked_neg()
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
Number::UInt64(v) => {
if let Ok(v) = i64::try_from(*v) {
v.checked_neg()
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
Err(Error::Message("Int64 overflow".to_string()))
}
}
Number::Float64(v) => Ok(Number::Float64(*v * -1.0)),
Number::Decimal64(v) => {
let neg_dec = Decimal64 {
scale: v.scale,
value: -v.value,
};
Ok(Number::Decimal64(neg_dec))
}
Number::Decimal128(v) => {
let neg_dec = Decimal128 {
scale: v.scale,
value: -v.value,
};
Ok(Number::Decimal128(neg_dec))
}
Number::Decimal256(v) => {
let Some(neg_value) = v.value.checked_neg() else {
return Err(Error::Message("Decimal256 overflow".to_string()));
};
let neg_dec = Decimal256 {
scale: v.scale,
value: neg_value,
};
Ok(Number::Decimal256(neg_dec))
}
}
}
pub fn add(&self, other: Number) -> Result<Number> {
match (self, other) {
(Number::Int64(a), Number::Int64(b)) => a
.checked_add(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
(Number::UInt64(a), Number::UInt64(b)) => a
.checked_add(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string())),
(Number::Int64(a), Number::UInt64(b)) => {
if *a < 0 {
a.checked_add(b as i64)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
(*a as u64)
.checked_add(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::UInt64(a), Number::Int64(b)) => {
if b < 0 {
(*a as i64)
.checked_add(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
a.checked_add(b as u64)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::Float64(a), Number::Float64(b)) => Ok(Number::Float64(a + b)),
(a, b) => {
let a_float = a.as_f64();
let b_float = b.as_f64();
Ok(Number::Float64(a_float + b_float))
}
}
}
pub fn sub(&self, other: Number) -> Result<Number> {
match (self, other) {
(Number::Int64(a), Number::Int64(b)) => a
.checked_sub(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
(Number::UInt64(a), Number::UInt64(b)) => (*a as i64)
.checked_sub(b as i64)
.map(Number::Int64)
.ok_or(Error::Message("UInt64 overflow".to_string())),
(Number::Int64(a), Number::UInt64(b)) => a
.checked_sub(b as i64)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
(Number::UInt64(a), Number::Int64(b)) => (*a as i64)
.checked_sub(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
(Number::Float64(a), Number::Float64(b)) => Ok(Number::Float64(a - b)),
(a, b) => {
let a_float = a.as_f64();
let b_float = b.as_f64();
Ok(Number::Float64(a_float - b_float))
}
}
}
pub fn mul(&self, other: Number) -> Result<Number> {
match (self, other) {
(Number::Int64(a), Number::Int64(b)) => a
.checked_mul(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string())),
(Number::UInt64(a), Number::UInt64(b)) => a
.checked_mul(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string())),
(Number::Int64(a), Number::UInt64(b)) => {
if *a < 0 {
a.checked_mul(b as i64)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
(*a as u64)
.checked_mul(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::UInt64(a), Number::Int64(b)) => {
if b < 0 {
(*a as i64)
.checked_mul(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
a.checked_mul(b as u64)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::Float64(a), Number::Float64(b)) => Ok(Number::Float64(a * b)),
(a, b) => {
let a_float = a.as_f64();
let b_float = b.as_f64();
Ok(Number::Float64(a_float * b_float))
}
}
}
pub fn div(&self, other: Number) -> Result<Number> {
let a_float = self.as_f64();
let b_float = other.as_f64();
if b_float == 0.0 {
return Err(Error::Message("Division by zero".to_string()));
}
Ok(Number::Float64(a_float / b_float))
}
pub fn rem(&self, other: Number) -> Result<Number> {
match (self, other) {
(Number::Int64(a), Number::Int64(b)) => {
if b == 0 {
return Err(Error::Message("Division by zero".to_string()));
}
a.checked_rem(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
}
(Number::UInt64(a), Number::UInt64(b)) => {
if b == 0 {
return Err(Error::Message("Division by zero".to_string()));
}
a.checked_rem(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
(Number::Int64(a), Number::UInt64(b)) => {
if b == 0 {
return Err(Error::Message("Division by zero".to_string()));
}
if *a < 0 {
a.checked_rem(b as i64)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
(*a as u64)
.checked_rem(b)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::UInt64(a), Number::Int64(b)) => {
if b == 0 {
return Err(Error::Message("Division by zero".to_string()));
}
if b < 0 {
(*a as i64)
.checked_rem(b)
.map(Number::Int64)
.ok_or(Error::Message("Int64 overflow".to_string()))
} else {
a.checked_rem(b as u64)
.map(Number::UInt64)
.ok_or(Error::Message("UInt64 overflow".to_string()))
}
}
(Number::Float64(a), Number::Float64(b)) => {
if b == 0.0 {
return Err(Error::Message("Division by zero".to_string()));
}
Ok(Number::Float64(a % b))
}
(a, b) => {
let a_float = a.as_f64();
let b_float = b.as_f64();
if b_float == 0.0 {
return Err(Error::Message("Division by zero".to_string()));
}
Ok(Number::Float64(a_float % b_float))
}
}
}
}
fn exact_float_to_int<T>(value: f64) -> Option<T>
where
T: Bounded + AsPrimitive<f64>,
f64: AsPrimitive<T>,
{
if !value.is_finite() || value.fract() != 0.0 {
return None;
}
if fits_float_target_range::<T>(value) {
Some(value.as_())
} else {
None
}
}
fn round_float_to_int<T>(value: f64) -> Option<T>
where
T: Bounded + AsPrimitive<f64>,
f64: AsPrimitive<T>,
{
if !value.is_finite() {
return None;
}
let rounded = value.round();
if fits_float_target_range::<T>(rounded) {
Some(rounded.as_())
} else {
None
}
}
#[inline]
fn fits_float_target_range<T>(value: f64) -> bool
where
T: Bounded + AsPrimitive<f64>,
{
let lower = T::min_value().as_();
let upper_exclusive = if lower < 0.0 {
-lower
} else {
T::max_value().as_() + 1.0
};
value >= lower && value < upper_exclusive
}
fn exact_decimal_i128(value: i128, scale: u8) -> Option<i128> {
if scale == 0 {
return Some(value);
}
let Some(divisor) = I128_POWERS_OF_10.get(scale as usize) else {
return if value == 0 { Some(0) } else { None };
};
if value % divisor == 0 {
Some(value / divisor)
} else {
None
}
}
fn round_decimal_i128(value: i128, scale: u8) -> Option<i128> {
if scale == 0 {
return Some(value);
}
let Some(divisor) = I128_POWERS_OF_10.get(scale as usize) else {
return Some(0);
};
let quotient = value / divisor;
let remainder = value % divisor;
let abs_remainder = remainder.unsigned_abs();
let divisor = *divisor as u128;
let round_up = abs_remainder >= divisor - abs_remainder;
if !round_up {
Some(quotient)
} else if value >= 0 {
quotient.checked_add(1)
} else {
quotient.checked_sub(1)
}
}
#[inline]
fn signed_i256_from_abs(abs: U256, negative: bool) -> Option<i256> {
let value = i256::try_from(abs).ok()?;
if negative {
i256::ZERO.checked_sub(value)
} else {
Some(value)
}
}
fn exact_decimal_i256(value: i256, scale: u8) -> Option<i256> {
if scale == 0 {
return Some(value);
}
let Some(divisor) = U256::new(10).checked_pow(scale as u32) else {
return if value == i256::ZERO {
Some(i256::ZERO)
} else {
None
};
};
let negative = value < i256::ZERO;
let abs_value = value.unsigned_abs();
let quotient = abs_value / divisor;
let remainder = abs_value % divisor;
if remainder != U256::ZERO {
return None;
}
signed_i256_from_abs(quotient, negative)
}
fn round_decimal_i256(value: i256, scale: u8) -> Option<i256> {
if scale == 0 {
return Some(value);
}
let Some(divisor) = U256::new(10).checked_pow(scale as u32) else {
return Some(i256::ZERO);
};
let negative = value < i256::ZERO;
let abs_value = value.unsigned_abs();
let quotient = abs_value / divisor;
let remainder = abs_value % divisor;
let round_up = remainder >= divisor - remainder;
let rounded = if round_up {
quotient.checked_add(U256::new(1))?
} else {
quotient
};
signed_i256_from_abs(rounded, negative)
}
impl Default for Number {
#[inline]
fn default() -> Self {
Number::UInt64(0)
}
}
impl PartialEq for Number {
#[inline]
fn eq(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Equal
}
}
impl PartialEq<&Number> for Number {
#[inline]
fn eq(&self, other: &&Number) -> bool {
self.eq(*other)
}
}
impl PartialEq<Number> for &Number {
#[inline]
fn eq(&self, other: &Number) -> bool {
(*self).eq(other)
}
}
impl Eq for Number {}
impl PartialOrd for Number {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl PartialOrd<&Number> for Number {
#[inline]
fn partial_cmp(&self, other: &&Number) -> Option<Ordering> {
self.partial_cmp(*other)
}
}
impl PartialOrd<Number> for &Number {
#[inline]
fn partial_cmp(&self, other: &Number) -> Option<Ordering> {
(*self).partial_cmp(other)
}
}
impl Ord for Number {
#[inline]
fn cmp(&self, other: &Self) -> Ordering {
match (self, other) {
(Number::Int64(l), Number::Int64(r)) => l.cmp(r),
(Number::UInt64(l), Number::UInt64(r)) => l.cmp(r),
(Number::Float64(l), Number::Float64(r)) => OrderedFloat(*l).cmp(&OrderedFloat(*r)),
(Number::Decimal64(l), Number::Decimal64(r)) => {
if l.scale == r.scale {
l.value.cmp(&r.value)
} else {
if let Some((l_val, r_val)) =
adjust_decimal_scales(l.value as i128, l.scale, r.value as i128, r.scale)
{
l_val.cmp(&r_val)
} else {
let l = OrderedFloat(self.as_f64());
let r = OrderedFloat(other.as_f64());
l.cmp(&r)
}
}
}
(Number::Decimal128(l), Number::Decimal128(r)) => {
if l.scale == r.scale {
l.value.cmp(&r.value)
} else {
if let Some((l_val, r_val)) =
adjust_decimal_scales(l.value, l.scale, r.value, r.scale)
{
l_val.cmp(&r_val)
} else {
let l = OrderedFloat(self.as_f64());
let r = OrderedFloat(other.as_f64());
l.cmp(&r)
}
}
}
(Number::Decimal256(l), Number::Decimal256(r)) => {
if l.scale == r.scale {
l.value.cmp(&r.value)
} else {
let scale_diff = l.scale as i32 - r.scale as i32;
if scale_diff > 0 {
let scale_factor = i256::from(10).pow(scale_diff as u32);
if let Some(r_val) = r.value.checked_mul(scale_factor) {
return l.value.cmp(&r_val);
}
} else {
let scale_factor = i256::from(10).pow((-scale_diff) as u32);
if let Some(l_val) = l.value.checked_mul(scale_factor) {
return l_val.cmp(&r.value);
}
}
let l = OrderedFloat(self.as_f64());
let r = OrderedFloat(other.as_f64());
l.cmp(&r)
}
}
(Number::Int64(l), Number::UInt64(r)) => {
if *l < 0 {
Ordering::Less
} else {
(*l as u64).cmp(r)
}
}
(Number::UInt64(l), Number::Int64(r)) => {
if *r < 0 {
Ordering::Greater
} else {
l.cmp(&(*r as u64))
}
}
(Number::Decimal64(_), Number::Int64(r)) => {
let r_decimal = Decimal64 {
scale: 0,
value: *r,
};
self.cmp(&Number::Decimal64(r_decimal))
}
(Number::Int64(l), Number::Decimal64(_)) => {
let l_decimal = Decimal64 {
scale: 0,
value: *l,
};
Number::Decimal64(l_decimal).cmp(other)
}
(Number::Decimal64(_), Number::UInt64(r)) => {
if *r <= i64::MAX as u64 {
let r_decimal = Decimal64 {
scale: 0,
value: *r as i64,
};
self.cmp(&Number::Decimal64(r_decimal))
} else {
let r_decimal = Decimal128 {
scale: 0,
value: *r as i128,
};
self.cmp(&Number::Decimal128(r_decimal))
}
}
(Number::UInt64(l), Number::Decimal64(_)) => {
if *l <= i64::MAX as u64 {
let l_decimal = Decimal64 {
scale: 0,
value: *l as i64,
};
Number::Decimal64(l_decimal).cmp(other)
} else {
let l_decimal = Decimal128 {
scale: 0,
value: *l as i128,
};
Number::Decimal128(l_decimal).cmp(other)
}
}
(Number::Decimal128(_), Number::Int64(r)) => {
let r_decimal = Decimal128 {
scale: 0,
value: *r as i128,
};
self.cmp(&Number::Decimal128(r_decimal))
}
(Number::Int64(l), Number::Decimal128(_)) => {
let l_decimal = Decimal128 {
scale: 0,
value: *l as i128,
};
Number::Decimal128(l_decimal).cmp(other)
}
(Number::Decimal128(_), Number::UInt64(r)) => {
let r_decimal = Decimal128 {
scale: 0,
value: *r as i128,
};
self.cmp(&Number::Decimal128(r_decimal))
}
(Number::UInt64(l), Number::Decimal128(_)) => {
let l_decimal = Decimal128 {
scale: 0,
value: *l as i128,
};
Number::Decimal128(l_decimal).cmp(other)
}
(Number::Decimal256(_), Number::Int64(r)) => {
let r_decimal = Decimal256 {
scale: 0,
value: i256::from(*r),
};
self.cmp(&Number::Decimal256(r_decimal))
}
(Number::Int64(l), Number::Decimal256(_)) => {
let l_decimal = Decimal256 {
scale: 0,
value: i256::from(*l),
};
Number::Decimal256(l_decimal).cmp(other)
}
(Number::Decimal256(_), Number::UInt64(r)) => {
let r_decimal = Decimal256 {
scale: 0,
value: i256::from(*r),
};
self.cmp(&Number::Decimal256(r_decimal))
}
(Number::UInt64(l), Number::Decimal256(_)) => {
let l_decimal = Decimal256 {
scale: 0,
value: i256::from(*l),
};
Number::Decimal256(l_decimal).cmp(other)
}
(Number::Decimal64(l), Number::Decimal128(_)) => {
let l_decimal = Decimal128 {
scale: l.scale,
value: l.value as i128,
};
Number::Decimal128(l_decimal).cmp(other)
}
(Number::Decimal128(_), Number::Decimal64(r)) => {
let r_decimal = Decimal128 {
scale: r.scale,
value: r.value as i128,
};
self.cmp(&Number::Decimal128(r_decimal))
}
(Number::Decimal64(l), Number::Decimal256(_)) => {
let l_decimal = Decimal256 {
scale: l.scale,
value: i256::from(l.value),
};
Number::Decimal256(l_decimal).cmp(other)
}
(Number::Decimal256(_), Number::Decimal64(r)) => {
let r_decimal = Decimal256 {
scale: r.scale,
value: i256::from(r.value),
};
self.cmp(&Number::Decimal256(r_decimal))
}
(Number::Decimal128(l), Number::Decimal256(_)) => {
let l_decimal = Decimal256 {
scale: l.scale,
value: i256::from(l.value),
};
Number::Decimal256(l_decimal).cmp(other)
}
(Number::Decimal256(_), Number::Decimal128(r)) => {
let r_decimal = Decimal256 {
scale: r.scale,
value: i256::from(r.value),
};
self.cmp(&Number::Decimal256(r_decimal))
}
(_, _) => {
let l = OrderedFloat(self.as_f64());
let r = OrderedFloat(other.as_f64());
l.cmp(&r)
}
}
}
}
fn adjust_decimal_scales(
l_val: i128,
l_scale: u8,
r_val: i128,
r_scale: u8,
) -> Option<(i128, i128)> {
let scale_diff = l_scale as i32 - r_scale as i32;
match scale_diff.cmp(&0) {
Ordering::Greater => {
let scale_factor = 10_i128.pow(scale_diff as u32);
let r_val = r_val.checked_mul(scale_factor)?;
Some((l_val, r_val))
}
Ordering::Less => {
let scale_factor = 10_i128.pow((-scale_diff) as u32);
let l_val = l_val.checked_mul(scale_factor)?;
Some((l_val, r_val))
}
Ordering::Equal => {
Some((l_val, r_val))
}
}
}
impl Display for Number {
fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
match self {
Number::Int64(v) => {
let mut buffer = itoa::Buffer::new();
let s = buffer.format(*v);
write!(f, "{}", s)
}
Number::UInt64(v) => {
let mut buffer = itoa::Buffer::new();
let s = buffer.format(*v);
write!(f, "{}", s)
}
Number::Float64(v) => {
let mut buffer = zmij::Buffer::new();
let s = buffer.format(*v);
write!(f, "{}", s)
}
Number::Decimal64(v) => format_decimal_i128(f, v.value as i128, v.scale as usize),
Number::Decimal128(v) => format_decimal_i128(f, v.value, v.scale as usize),
Number::Decimal256(v) => format_decimal_i256(f, v.value, v.scale as usize),
}
}
}
fn format_decimal_i128(
f: &mut impl std::fmt::Write,
value: i128,
scale: usize,
) -> std::fmt::Result {
let mut itoa_buf = itoa::Buffer::new();
if scale == 0 {
f.write_str(itoa_buf.format(value))
} else {
let value = if value < 0 {
f.write_str("-")?;
-value
} else {
value
};
let pow_scale = I128_POWERS_OF_10[scale];
let integer_part = value / pow_scale;
f.write_str(itoa_buf.format(integer_part))?;
f.write_str(".")?;
let fractional_part = (value % pow_scale).abs();
let fractional_str = itoa_buf.format(fractional_part);
let leading_zeros_count = scale - fractional_str.len();
if leading_zeros_count > 0 {
let zeros = LEADING_ZEROS[leading_zeros_count];
f.write_str(zeros)?;
}
f.write_str(fractional_str)
}
}
fn format_decimal_i256(
f: &mut impl std::fmt::Write,
value: i256,
scale: usize,
) -> std::fmt::Result {
let value = if value < i256::ZERO {
f.write_str("-")?;
-value
} else {
value
};
let high_part = (value / *I256_DIVIDE_SCALE).as_i128();
let low_part = (value % *I256_DIVIDE_SCALE).as_i128();
let mut itoa_buf = itoa::Buffer::new();
if scale == 0 {
if high_part > 0 {
f.write_str(itoa_buf.format(high_part))?;
let low_str = itoa_buf.format(low_part);
let zeros_count = I128_SCALE - low_str.len();
if zeros_count > 0 {
let zeros = LEADING_ZEROS[zeros_count];
f.write_str(zeros)?;
}
f.write_str(low_str)
} else {
f.write_str(itoa_buf.format(low_part))
}
}
else if scale >= I128_SCALE {
let high_scale = scale - I128_SCALE;
let pow_scale = I128_POWERS_OF_10[high_scale];
let int_part = high_part / pow_scale;
f.write_str(itoa_buf.format(int_part))?;
f.write_str(".")?;
if high_scale > 0 {
let high_frac_part = high_part % pow_scale;
let high_frac_str = itoa_buf.format(high_frac_part);
let high_zeros_count = high_scale - high_frac_str.len();
if high_zeros_count > 0 {
let zeros = LEADING_ZEROS[high_zeros_count];
f.write_str(zeros)?;
}
f.write_str(high_frac_str)?;
}
let mut low_buf = itoa::Buffer::new();
let low_frac_str = low_buf.format(low_part);
let low_zeros_count = I128_SCALE - low_frac_str.len();
if low_zeros_count > 0 {
let low_zeros = LEADING_ZEROS[low_zeros_count];
f.write_str(low_zeros)?;
}
f.write_str(low_frac_str)
}
else {
if high_part > 0 {
f.write_str(itoa_buf.format(high_part))?;
}
let pow_scale = I128_POWERS_OF_10[scale];
let int_part = low_part / pow_scale;
let int_str = itoa_buf.format(int_part);
if high_part > 0 {
let int_zeros_count = I128_SCALE - scale - int_str.len();
if int_zeros_count > 0 {
let int_zeros = LEADING_ZEROS[int_zeros_count];
f.write_str(int_zeros)?;
}
}
f.write_str(int_str)?;
f.write_str(".")?;
let frac_part = low_part % pow_scale;
let mut frac_buf = itoa::Buffer::new();
let frac_str = frac_buf.format(frac_part);
let frac_zeros_count = scale - frac_str.len();
if frac_zeros_count > 0 {
let frac_zeros = LEADING_ZEROS[frac_zeros_count];
f.write_str(frac_zeros)?;
}
f.write_str(frac_str)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::cmp::Ordering;
#[test]
fn test_number_comparison() {
assert_eq!(Number::Int64(10).cmp(&Number::Int64(5)), Ordering::Greater);
assert_eq!(Number::Int64(5).cmp(&Number::Int64(10)), Ordering::Less);
assert_eq!(Number::Int64(5).cmp(&Number::Int64(5)), Ordering::Equal);
assert_eq!(
Number::UInt64(10).cmp(&Number::UInt64(5)),
Ordering::Greater
);
assert_eq!(Number::UInt64(5).cmp(&Number::UInt64(10)), Ordering::Less);
assert_eq!(Number::UInt64(5).cmp(&Number::UInt64(5)), Ordering::Equal);
assert_eq!(
Number::Float64(10.0).cmp(&Number::Float64(5.0)),
Ordering::Greater
);
assert_eq!(
Number::Float64(5.0).cmp(&Number::Float64(10.0)),
Ordering::Less
);
assert_eq!(
Number::Float64(5.0).cmp(&Number::Float64(5.0)),
Ordering::Equal
);
assert_eq!(Number::Int64(10).cmp(&Number::UInt64(5)), Ordering::Greater);
assert_eq!(Number::Int64(5).cmp(&Number::UInt64(10)), Ordering::Less);
assert_eq!(Number::Int64(5).cmp(&Number::UInt64(5)), Ordering::Equal);
assert_eq!(Number::Int64(-5).cmp(&Number::UInt64(5)), Ordering::Less);
assert_eq!(Number::UInt64(10).cmp(&Number::Int64(5)), Ordering::Greater);
assert_eq!(Number::UInt64(5).cmp(&Number::Int64(10)), Ordering::Less);
assert_eq!(Number::UInt64(5).cmp(&Number::Int64(5)), Ordering::Equal);
assert_eq!(Number::UInt64(5).cmp(&Number::Int64(-5)), Ordering::Greater);
let d1 = Decimal64 {
scale: 2,
value: 1234,
}; let d2 = Decimal64 {
scale: 2,
value: 5678,
}; assert_eq!(
Number::Decimal64(d1.clone()).cmp(&Number::Decimal64(d2.clone())),
Ordering::Less
);
assert_eq!(
Number::Decimal64(d2.clone()).cmp(&Number::Decimal64(d1.clone())),
Ordering::Greater
);
assert_eq!(
Number::Decimal64(d1.clone()).cmp(&Number::Decimal64(d1.clone())),
Ordering::Equal
);
let d3 = Decimal64 {
scale: 3,
value: 12340,
}; assert_eq!(
Number::Decimal64(d1.clone()).cmp(&Number::Decimal64(d3.clone())),
Ordering::Equal
);
let d4 = Decimal64 {
scale: 1,
value: 123,
}; assert_eq!(
Number::Decimal64(d1.clone()).cmp(&Number::Decimal64(d4.clone())),
Ordering::Greater
);
let d5 = Decimal128 {
scale: 2,
value: 1234,
}; let d6 = Decimal128 {
scale: 2,
value: 5678,
}; assert_eq!(
Number::Decimal128(d5.clone()).cmp(&Number::Decimal128(d6.clone())),
Ordering::Less
);
let d7 = Decimal256 {
scale: 2,
value: i256::from(1234),
}; let d8 = Decimal256 {
scale: 2,
value: i256::from(5678),
}; assert_eq!(
Number::Decimal256(d7.clone()).cmp(&Number::Decimal256(d8.clone())),
Ordering::Less
);
assert_eq!(
Number::Int64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 0,
value: 12
})),
Ordering::Equal
);
assert_eq!(
Number::Int64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 1,
value: 120
})),
Ordering::Equal
);
assert_eq!(
Number::Int64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 1,
value: 121
})),
Ordering::Less
);
assert_eq!(
Number::Int64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 1,
value: 119
})),
Ordering::Greater
);
assert_eq!(
Number::UInt64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 0,
value: 12
})),
Ordering::Equal
);
assert_eq!(
Number::UInt64(12).cmp(&Number::Decimal64(Decimal64 {
scale: 1,
value: 120
})),
Ordering::Equal
);
assert_eq!(
Number::Float64(12.34).cmp(&Number::Decimal64(Decimal64 {
scale: 2,
value: 1234
})),
Ordering::Equal
);
assert_eq!(
Number::Float64(12.34).cmp(&Number::Decimal64(Decimal64 {
scale: 2,
value: 1235
})),
Ordering::Less
);
assert_eq!(
Number::Decimal64(Decimal64 {
scale: 2,
value: 1234
})
.cmp(&Number::Decimal128(Decimal128 {
scale: 2,
value: 1234
})),
Ordering::Equal
);
assert_eq!(
Number::Decimal64(Decimal64 {
scale: 2,
value: 1234
})
.cmp(&Number::Decimal128(Decimal128 {
scale: 2,
value: 5678
})),
Ordering::Less
);
assert_eq!(
Number::Decimal64(Decimal64 {
scale: 2,
value: 1234
})
.cmp(&Number::Decimal256(Decimal256 {
scale: 2,
value: i256::from(1234)
})),
Ordering::Equal
);
assert_eq!(
Number::Decimal128(Decimal128 {
scale: 2,
value: 1234
})
.cmp(&Number::Decimal256(Decimal256 {
scale: 2,
value: i256::from(1234)
})),
Ordering::Equal
);
assert_eq!(
Number::Decimal64(Decimal64 {
scale: 2,
value: 1234
})
.cmp(&Number::Decimal128(Decimal128 {
scale: 3,
value: 12340
})),
Ordering::Equal
);
let large_int = i64::MAX;
let large_uint = u64::MAX;
let large_decimal = Decimal128 {
scale: 0,
value: i128::from(large_int),
};
assert_eq!(
Number::Int64(large_int).cmp(&Number::Decimal128(large_decimal.clone())),
Ordering::Equal
);
assert_eq!(
Number::Decimal128(large_decimal.clone()).cmp(&Number::Int64(large_int)),
Ordering::Equal
);
assert_eq!(
Number::UInt64(large_uint).cmp(&Number::Decimal128(large_decimal.clone())),
Ordering::Greater
);
assert_eq!(
Number::Decimal128(large_decimal).cmp(&Number::UInt64(large_uint)),
Ordering::Less
);
let neg_int = -100;
let neg_decimal = Decimal64 {
scale: 0,
value: -100,
};
assert_eq!(
Number::Int64(neg_int).cmp(&Number::Decimal64(neg_decimal.clone())),
Ordering::Equal
);
assert_eq!(
Number::Decimal64(neg_decimal).cmp(&Number::UInt64(100)),
Ordering::Less
);
assert_eq!(Number::Int64(0).cmp(&Number::UInt64(0)), Ordering::Equal);
assert_eq!(
Number::Int64(0).cmp(&Number::Decimal64(Decimal64 { scale: 0, value: 0 })),
Ordering::Equal
);
assert_eq!(
Number::Int64(0).cmp(&Number::Decimal64(Decimal64 { scale: 5, value: 0 })),
Ordering::Equal
);
}
#[test]
fn test_exact_integer_casts() {
let decimal64 = Number::Decimal64(Decimal64 {
scale: 1,
value: 1230,
});
assert_eq!(decimal64.as_i128(), Some(123));
assert_eq!(decimal64.as_i64(), Some(123));
assert_eq!(decimal64.as_u64(), Some(123));
let decimal128 = Number::Decimal128(Decimal128 {
scale: 1,
value: 1230,
});
assert_eq!(decimal128.as_i128(), Some(123));
assert_eq!(decimal128.as_i64(), Some(123));
assert_eq!(decimal128.as_u64(), Some(123));
let negative_decimal128 = Number::Decimal128(Decimal128 {
scale: 1,
value: -1230,
});
assert_eq!(negative_decimal128.as_i128(), Some(-123));
assert_eq!(negative_decimal128.as_i64(), Some(-123));
assert_eq!(negative_decimal128.as_u64(), None);
let non_integer_decimal64 = Number::Decimal64(Decimal64 {
scale: 1,
value: 1234,
});
assert_eq!(non_integer_decimal64.as_i128(), None);
assert_eq!(non_integer_decimal64.as_i64(), None);
assert_eq!(non_integer_decimal64.as_u64(), None);
let decimal256 = Number::Decimal256(Decimal256 {
scale: 1,
value: i256::from(1230),
});
assert_eq!(decimal256.as_i128(), Some(123));
assert_eq!(decimal256.as_i64(), Some(123));
assert_eq!(decimal256.as_u64(), Some(123));
let float = Number::Float64(123.0);
assert_eq!(float.as_i128(), Some(123));
assert_eq!(float.as_i64(), Some(123));
assert_eq!(float.as_u64(), Some(123));
let non_integer_float = Number::Float64(123.1);
assert_eq!(non_integer_float.as_i128(), None);
assert_eq!(non_integer_float.as_i64(), None);
assert_eq!(non_integer_float.as_u64(), None);
let u64_upper_bound = Number::Float64((u64::MAX as f64) + 1.0);
assert_eq!(u64_upper_bound.as_u64(), None);
}
#[test]
fn test_rounded_integer_casts() {
let decimal128 = Number::Decimal128(Decimal128 {
scale: 1,
value: 1235,
});
assert_eq!(decimal128.to_i128(), Some(124));
assert_eq!(decimal128.to_i64(), Some(124));
assert_eq!(decimal128.to_u64(), Some(124));
let negative_decimal128 = Number::Decimal128(Decimal128 {
scale: 1,
value: -1235,
});
assert_eq!(negative_decimal128.to_i128(), Some(-124));
assert_eq!(negative_decimal128.to_i64(), Some(-124));
assert_eq!(negative_decimal128.to_u64(), None);
let small_negative_decimal64 = Number::Decimal64(Decimal64 {
scale: 1,
value: -4,
});
assert_eq!(small_negative_decimal64.to_i64(), Some(0));
assert_eq!(small_negative_decimal64.to_u64(), Some(0));
let decimal256 = Number::Decimal256(Decimal256 {
scale: 1,
value: i256::from(1234),
});
assert_eq!(decimal256.to_i128(), Some(123));
assert_eq!(decimal256.to_i64(), Some(123));
assert_eq!(decimal256.to_u64(), Some(123));
let float = Number::Float64(123.4);
assert_eq!(float.to_i128(), Some(123));
assert_eq!(float.to_i64(), Some(123));
assert_eq!(float.to_u64(), Some(123));
let half_up = Number::Float64(123.5);
assert_eq!(half_up.to_i128(), Some(124));
assert_eq!(half_up.to_i64(), Some(124));
assert_eq!(half_up.to_u64(), Some(124));
let negative_half_up = Number::Float64(-123.5);
assert_eq!(negative_half_up.to_i128(), Some(-124));
assert_eq!(negative_half_up.to_i64(), Some(-124));
assert_eq!(negative_half_up.to_u64(), None);
let small_negative = Number::Float64(-0.4);
assert_eq!(small_negative.to_i64(), Some(0));
assert_eq!(small_negative.to_u64(), Some(0));
let nan = Number::Float64(f64::NAN);
assert_eq!(nan.to_i128(), None);
assert_eq!(nan.to_i64(), None);
assert_eq!(nan.to_u64(), None);
let inf = Number::Float64(f64::INFINITY);
assert_eq!(inf.to_i128(), None);
assert_eq!(inf.to_i64(), None);
assert_eq!(inf.to_u64(), None);
let large = Number::Float64(1e100);
assert_eq!(large.to_i128(), None);
assert_eq!(large.to_i64(), None);
assert_eq!(large.to_u64(), None);
let i64_upper_bound = Number::Float64(-(i64::MIN as f64));
assert_eq!(i64_upper_bound.to_i64(), None);
let u64_upper_bound = Number::Float64((u64::MAX as f64) + 1.0);
assert_eq!(u64_upper_bound.to_u64(), None);
let overflowing_decimal128 = Number::Decimal128(Decimal128 {
scale: 1,
value: i128::from(i64::MAX) * 10 + 5,
});
assert_eq!(overflowing_decimal128.to_i64(), None);
}
}