use crate::numeric::{NumericAddable, NumericComparable, ToBigDecimal};
use std::cmp::Ordering;
use std::str::FromStr;
use substreams::scalar::{BigDecimal, BigInt};
macro_rules! impl_numeric_for_integer {
($($t:ty),*) => {
$(
impl ToBigDecimal for $t {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from(*self)
}
}
impl NumericAddable for $t {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += BigDecimal::from(*self);
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= BigDecimal::from(*self);
}
}
)*
};
}
macro_rules! impl_numeric_for_integer_via_cast {
($($t:ty => $cast:ty),*) => {
$(
impl ToBigDecimal for $t {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from(*self as $cast)
}
}
impl NumericAddable for $t {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += BigDecimal::from(*self as $cast);
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= BigDecimal::from(*self as $cast);
}
}
)*
};
}
impl_numeric_for_integer!(i32, i64, u32, u64);
impl_numeric_for_integer_via_cast!(
i8 => i64,
i16 => i64,
u8 => u64,
u16 => u64,
isize => i64,
usize => u64
);
impl ToBigDecimal for i128 {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from_str(&self.to_string())
.expect("i128 should always convert to BigDecimal")
}
}
impl NumericAddable for i128 {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += self.to_big_decimal();
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= self.to_big_decimal();
}
}
impl ToBigDecimal for u128 {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from_str(&self.to_string())
.expect("u128 should always convert to BigDecimal")
}
}
impl NumericAddable for u128 {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += self.to_big_decimal();
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= self.to_big_decimal();
}
}
impl ToBigDecimal for BigDecimal {
fn to_big_decimal(&self) -> BigDecimal {
self.clone()
}
}
impl NumericAddable for BigDecimal {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += self;
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= self;
}
}
impl ToBigDecimal for &BigDecimal {
fn to_big_decimal(&self) -> BigDecimal {
(*self).clone()
}
}
impl NumericAddable for &BigDecimal {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += *self;
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= *self;
}
}
impl ToBigDecimal for BigInt {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from(self.clone())
}
}
impl NumericAddable for BigInt {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += BigDecimal::from(self.clone());
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= BigDecimal::from(self.clone());
}
}
impl ToBigDecimal for &BigInt {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from((*self).clone())
}
}
impl NumericAddable for &BigInt {
fn add_assign_to(&self, target: &mut BigDecimal) {
*target += BigDecimal::from((*self).clone());
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
*target -= BigDecimal::from((*self).clone());
}
}
macro_rules! impl_numeric_for_string {
($($t:ty),*) => {
$(
impl ToBigDecimal for $t {
fn to_big_decimal(&self) -> BigDecimal {
BigDecimal::from_str(self).unwrap_or_else(|_| {
panic!(
"add/sub() requires a valid numeric value, got: {}",
self
)
})
}
}
impl NumericAddable for $t {
fn add_assign_to(&self, target: &mut BigDecimal) {
let value = self.to_big_decimal();
*target += value;
}
fn sub_assign_from(&self, target: &mut BigDecimal) {
let value = self.to_big_decimal();
*target -= value;
}
}
)*
};
}
impl_numeric_for_string!(String, &str);
macro_rules! impl_numeric_comparable_for_integer {
($($t:ty),*) => {
$(
impl NumericComparable for $t {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
self.partial_cmp(other)
.expect(concat!("BigDecimal comparison should always succeed for ", stringify!($t)))
}
}
)*
};
}
impl_numeric_comparable_for_integer!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
impl NumericComparable for isize {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
(*self as i64).partial_cmp(other)
.expect("BigDecimal comparison should always succeed for isize")
}
}
impl NumericComparable for usize {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
(*self as u64).partial_cmp(other)
.expect("BigDecimal comparison should always succeed for usize")
}
}
impl NumericComparable for BigDecimal {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
self.cmp(other)
}
}
impl NumericComparable for &BigDecimal {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
(*self).cmp(other)
}
}
impl NumericComparable for BigInt {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
let self_bd = BigDecimal::from(self.clone());
self_bd.cmp(other)
}
}
impl NumericComparable for &BigInt {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
let self_bd = BigDecimal::from((*self).clone());
self_bd.cmp(other)
}
}