pub use df_derive_core::dataframe::{Columnar, ToDataFrame, ToDataFrameVec};
#[doc(hidden)]
pub mod __private {
pub use df_derive_core::dataframe::__private::{polars, polars_arrow};
}
pub trait Decimal128Encode {
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128>;
}
const MAX_I128_MANTISSA: i128 = 10_i128.pow(38);
impl Decimal128Encode for rust_decimal::Decimal {
#[inline]
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128> {
let source_scale = self.scale();
let mantissa: i128 = self.mantissa();
let rescaled = match source_scale.cmp(&target_scale) {
std::cmp::Ordering::Equal => mantissa,
std::cmp::Ordering::Less => {
let diff = target_scale - source_scale;
let pow = 10i128.pow(diff);
mantissa.checked_mul(pow)?
}
std::cmp::Ordering::Greater => {
let diff = source_scale - target_scale;
let pow = 10i128.pow(diff).cast_unsigned();
let neg = mantissa < 0;
let abs = mantissa.unsigned_abs();
let q = (abs / pow).cast_signed();
let r = abs % pow;
let half = pow / 2;
let rounded = match r.cmp(&half) {
std::cmp::Ordering::Greater => q + 1,
std::cmp::Ordering::Less => q,
std::cmp::Ordering::Equal => q + (q & 1),
};
if neg { -rounded } else { rounded }
}
};
if rescaled.unsigned_abs() >= MAX_I128_MANTISSA.cast_unsigned() {
return None;
}
Some(rescaled)
}
}
#[cfg(feature = "bigdecimal")]
impl Decimal128Encode for bigdecimal::BigDecimal {
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128> {
let target = i64::from(target_scale);
let rescaled = self.with_scale_round(target, bigdecimal::RoundingMode::HalfEven);
if rescaled.digits() > 38 {
return None;
}
let (bigint, _) = rescaled.into_bigint_and_exponent();
i128::try_from(bigint).ok()
}
}