ext/polars/src/conversion.rs in polars-df-0.1.4 vs ext/polars/src/conversion.rs in polars-df-0.1.5

- old
+ new

@@ -1,37 +1,60 @@ -use magnus::{class, RArray, Symbol, TryConvert, Value, QNIL}; +use magnus::{class, r_hash::ForEach, RArray, RHash, Symbol, TryConvert, Value, QNIL}; use polars::chunked_array::object::PolarsObjectSafe; use polars::chunked_array::ops::{FillNullLimit, FillNullStrategy}; use polars::datatypes::AnyValue; +use polars::frame::row::Row; use polars::frame::DataFrame; +use polars::io::avro::AvroCompression; use polars::prelude::*; use polars::series::ops::NullBehavior; use std::fmt::{Display, Formatter}; use std::hash::{Hash, Hasher}; -use crate::{RbDataFrame, RbPolarsErr, RbResult, RbSeries, RbValueError}; +use crate::{RbDataFrame, RbLazyFrame, RbPolarsErr, RbResult, RbSeries, RbValueError}; +pub(crate) fn slice_to_wrapped<T>(slice: &[T]) -> &[Wrap<T>] { + // Safety: + // Wrap is transparent. + unsafe { std::mem::transmute(slice) } +} + +#[repr(transparent)] pub struct Wrap<T>(pub T); +impl<T> Clone for Wrap<T> +where + T: Clone, +{ + fn clone(&self) -> Self { + Wrap(self.0.clone()) + } +} + impl<T> From<T> for Wrap<T> { fn from(t: T) -> Self { Wrap(t) } } -pub fn get_rbseq(obj: Value) -> RbResult<(RArray, usize)> { +pub(crate) fn get_rbseq(obj: Value) -> RbResult<(RArray, usize)> { let seq: RArray = obj.try_convert()?; let len = seq.len(); Ok((seq, len)) } -pub fn get_df(obj: Value) -> RbResult<DataFrame> { +pub(crate) fn get_df(obj: Value) -> RbResult<DataFrame> { let rbdf = obj.funcall::<_, _, &RbDataFrame>("_df", ())?; Ok(rbdf.df.borrow().clone()) } -pub fn get_series(obj: Value) -> RbResult<Series> { +pub(crate) fn get_lf(obj: Value) -> RbResult<LazyFrame> { + let rbdf = obj.funcall::<_, _, &RbLazyFrame>("_ldf", ())?; + Ok(rbdf.ldf.clone()) +} + +pub(crate) fn get_series(obj: Value) -> RbResult<Series> { let rbs = obj.funcall::<_, _, &RbSeries>("_s", ())?; Ok(rbs.series.borrow().clone()) } impl TryConvert for Wrap<Utf8Chunked> { @@ -169,10 +192,43 @@ ))) } } } +impl TryConvert for Wrap<AsofStrategy> { + fn try_convert(ob: Value) -> RbResult<Self> { + let parsed = match ob.try_convert::<String>()?.as_str() { + "backward" => AsofStrategy::Backward, + "forward" => AsofStrategy::Forward, + v => { + return Err(RbValueError::new_err(format!( + "strategy must be one of {{'backward', 'forward'}}, got {}", + v + ))) + } + }; + Ok(Wrap(parsed)) + } +} + +impl TryConvert for Wrap<Option<AvroCompression>> { + fn try_convert(ob: Value) -> RbResult<Self> { + let parsed = match ob.try_convert::<String>()?.as_str() { + "uncompressed" => None, + "snappy" => Some(AvroCompression::Snappy), + "deflate" => Some(AvroCompression::Deflate), + v => { + return Err(RbValueError::new_err(format!( + "compression must be one of {{'uncompressed', 'snappy', 'deflate'}}, got {}", + v + ))) + } + }; + Ok(Wrap(parsed)) + } +} + impl TryConvert for Wrap<CategoricalOrdering> { fn try_convert(ob: Value) -> RbResult<Self> { let parsed = match ob.try_convert::<String>()?.as_str() { "physical" => CategoricalOrdering::Physical, "lexical" => CategoricalOrdering::Lexical, @@ -460,10 +516,36 @@ } }; Ok(parsed) } +impl<'s> TryConvert for Wrap<Row<'s>> { + fn try_convert(ob: Value) -> RbResult<Self> { + let mut vals: Vec<Wrap<AnyValue<'s>>> = Vec::new(); + for item in ob.try_convert::<RArray>()?.each() { + vals.push(item?.try_convert::<Wrap<AnyValue<'s>>>()?); + } + let vals: Vec<AnyValue> = unsafe { std::mem::transmute(vals) }; + Ok(Wrap(Row(vals))) + } +} + +impl TryConvert for Wrap<Schema> { + fn try_convert(ob: Value) -> RbResult<Self> { + let dict = ob.try_convert::<RHash>()?; + + let mut schema = Vec::new(); + dict.foreach(|key: String, val: Wrap<DataType>| { + schema.push(Field::new(&key, val.0)); + Ok(ForEach::Continue) + }) + .unwrap(); + + Ok(Wrap(schema.into_iter().into())) + } +} + #[derive(Clone, Debug)] pub struct ObjectValue { pub inner: Value, } @@ -501,18 +583,31 @@ fn from(v: Value) -> Self { Self { inner: v } } } +impl TryConvert for ObjectValue { + fn try_convert(ob: Value) -> RbResult<Self> { + Ok(ObjectValue { inner: ob }) + } +} + impl From<&dyn PolarsObjectSafe> for &ObjectValue { fn from(val: &dyn PolarsObjectSafe) -> Self { unsafe { &*(val as *const dyn PolarsObjectSafe as *const ObjectValue) } } } +// TODO remove impl ObjectValue { pub fn to_object(&self) -> Value { self.inner + } +} + +impl From<ObjectValue> for Value { + fn from(val: ObjectValue) -> Self { + val.inner } } impl Default for ObjectValue { fn default() -> Self {