#![allow(clippy::multiple_crate_versions)]
pub mod dataframe {
use polars::prelude::{AnyValue, DataFrame, DataType, PolarsResult, Series};
#[cfg(feature = "rust_decimal")]
const DECIMAL128_MAX_SCALE: u32 = 38;
#[doc(hidden)]
pub mod __private {
pub use polars;
pub use polars_arrow;
}
pub trait ToDataFrame {
fn to_dataframe(&self) -> PolarsResult<DataFrame>;
fn empty_dataframe() -> PolarsResult<DataFrame>;
fn schema() -> PolarsResult<Vec<(String, DataType)>>;
}
pub trait Columnar: Sized {
fn columnar_to_dataframe(items: &[Self]) -> PolarsResult<DataFrame> {
let refs: Vec<&Self> = items.iter().collect();
Self::columnar_from_refs(&refs)
}
fn columnar_from_refs(items: &[&Self]) -> PolarsResult<DataFrame>;
}
pub trait ToDataFrameVec {
fn to_dataframe(&self) -> PolarsResult<DataFrame>;
}
impl<T> ToDataFrameVec for [T]
where
T: Columnar + ToDataFrame,
{
fn to_dataframe(&self) -> PolarsResult<DataFrame> {
if self.is_empty() {
return <T as ToDataFrame>::empty_dataframe();
}
<T as Columnar>::columnar_to_dataframe(self)
}
}
fn zero_column_dataframe_with_height(n: usize) -> PolarsResult<DataFrame> {
let dummy = Series::new_empty("_dummy".into(), &DataType::Null)
.extend_constant(AnyValue::Null, n)?;
let mut df = DataFrame::new_infer_height(vec![dummy.into()])?;
df.drop_in_place("_dummy")?;
Ok(df)
}
impl ToDataFrame for () {
fn to_dataframe(&self) -> PolarsResult<DataFrame> {
zero_column_dataframe_with_height(1)
}
fn empty_dataframe() -> PolarsResult<DataFrame> {
DataFrame::new_infer_height(vec![])
}
fn schema() -> PolarsResult<Vec<(String, DataType)>> {
Ok(Vec::new())
}
}
impl Columnar for () {
fn columnar_to_dataframe(items: &[Self]) -> PolarsResult<DataFrame> {
zero_column_dataframe_with_height(items.len())
}
fn columnar_from_refs(items: &[&Self]) -> PolarsResult<DataFrame> {
zero_column_dataframe_with_height(items.len())
}
}
pub trait Decimal128Encode {
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128>;
}
impl<T> Decimal128Encode for &T
where
T: Decimal128Encode + ?Sized,
{
#[inline]
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128> {
<T as Decimal128Encode>::try_to_i128_mantissa(*self, target_scale)
}
}
#[cfg(feature = "rust_decimal")]
impl Decimal128Encode for rust_decimal::Decimal {
#[inline]
fn try_to_i128_mantissa(&self, target_scale: u32) -> Option<i128> {
if target_scale > DECIMAL128_MAX_SCALE {
return None;
}
let source_scale = self.scale();
let mantissa: i128 = self.mantissa();
if source_scale == target_scale {
return Some(mantissa);
}
if source_scale < target_scale {
let diff = target_scale - source_scale;
let pow = 10i128.pow(diff);
return mantissa.checked_mul(pow);
}
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),
};
Some(if neg { -rounded } else { rounded })
}
}
}