Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 106 additions & 2 deletions src/numeric/impls.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::numeric::{NumericAddable, ToBigDecimal};
use crate::numeric::{NumericAddable, NumericComparable, ToBigDecimal};
use std::cmp::Ordering;
use std::str::FromStr;
use substreams::scalar::{BigDecimal, BigInt};

Expand Down Expand Up @@ -56,9 +57,46 @@ impl_numeric_for_integer_via_cast!(
i8 => i64,
i16 => i64,
u8 => u64,
u16 => u64
u16 => u64,
isize => i64,
usize => u64
);

// i128 and u128 - convert via string since BigInt doesn't support them directly
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()
Expand Down Expand Up @@ -155,3 +193,69 @@ macro_rules! impl_numeric_for_string {

// Apply to String and &str types
impl_numeric_for_string!(String, &str);

// ============================================================
// NumericComparable implementations
// ============================================================

// Macro for implementing NumericComparable on integer types using BigDecimal's native PartialOrd
macro_rules! impl_numeric_comparable_for_integer {
($($t:ty),*) => {
$(
impl NumericComparable for $t {
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering {
// Direct comparison using BigDecimal's PartialOrd<$t>
// This is zero-allocation for <type>
self.partial_cmp(other)
.expect(concat!("BigDecimal comparison should always succeed for ", stringify!($t)))
}
}
)*
};
}

// Apply to all primitive integer types including i128/u128
impl_numeric_comparable_for_integer!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);

// Specialized implementations for isize/usize (cast to i64/u64)
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")
}
}

// BigDecimal implementations
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)
}
}

// BigInt implementations - convert to BigDecimal for comparison
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)
}
}
2 changes: 1 addition & 1 deletion src/numeric/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod impls;
mod traits;

pub use traits::{NumericAddable, ToBigDecimal};
pub use traits::{NumericAddable, NumericComparable, ToBigDecimal};
13 changes: 13 additions & 0 deletions src/numeric/traits.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::cmp::Ordering;
use substreams::scalar::BigDecimal;

/// Trait for types that can be converted to BigDecimal
Expand Down Expand Up @@ -32,3 +33,15 @@ pub trait NumericAddable: ToBigDecimal {
/// For example: `50i64.sub_assign_from(&mut target)` will subtract 50 from target.
fn sub_assign_from(&self, target: &mut BigDecimal);
}

/// Trait for types that can be compared against a BigDecimal for min/max operations
///
/// This trait leverages BigDecimal's native PartialOrd implementations for primitive
/// types, enabling zero-allocation comparisons for integers.
pub trait NumericComparable: ToBigDecimal {
/// Compare self against a BigDecimal value
///
/// For primitive integers, this uses BigDecimal's native PartialOrd implementation
/// which requires no allocation. For other types, conversion may be needed.
fn cmp_to_big_decimal(&self, other: &BigDecimal) -> Ordering;
}
Loading
Loading