diff --git a/Cargo.lock b/Cargo.lock index 84ac0a30de..5cb307b5e0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1017,24 +1017,25 @@ dependencies = [ [[package]] name = "magnus" -version = "0.5.4" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b560c3c0284c9ec7c30b7ba823896387423225add3f107213a794b73853c7505" +checksum = "68e9585bfe236e88e6b10b6d8eb5349bd0e0009f3f9dff8d2e99a82601b33743" dependencies = [ "magnus-macros", "rb-sys", "rb-sys-env", + "seq-macro", ] [[package]] name = "magnus-macros" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cc17af1d45442c011aa579d727ec6cff8a69aea8a6bbad26736e7112d749bfb" +checksum = "5968c820e2960565f647819f5928a42d6e874551cab9d88d75e3e0660d7f71e3" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.26", ] [[package]] diff --git a/ext/polars/Cargo.toml b/ext/polars/Cargo.toml index e466d637e7..0744983fd7 100644 --- a/ext/polars/Cargo.toml +++ b/ext/polars/Cargo.toml @@ -12,7 +12,7 @@ crate-type = ["cdylib"] [dependencies] ahash = "0.8" chrono = "=0.4.24" -magnus = "0.5" +magnus = "0.6" polars-core = "0.31.1" serde_json = "1" smartstring = "1" diff --git a/ext/polars/src/apply/dataframe.rs b/ext/polars/src/apply/dataframe.rs index fbc8ed788a..fd3c4fc122 100644 --- a/ext/polars/src/apply/dataframe.rs +++ b/ext/polars/src/apply/dataframe.rs @@ -1,4 +1,4 @@ -use magnus::{class, IntoValue, RArray, TryConvert, Value}; +use magnus::{class, prelude::*, typed_data::Obj, IntoValue, RArray, TryConvert, Value}; use polars::prelude::*; use polars_core::frame::row::{rows_to_schema_first_non_null, Row}; use polars_core::series::SeriesIter; @@ -34,20 +34,20 @@ pub fn apply_lambda_unknown<'a>( null_count += 1; continue; } else if out.is_kind_of(class::true_class()) || out.is_kind_of(class::false_class()) { - let first_value = out.try_convert::().ok(); + let first_value = bool::try_convert(out).ok(); return Ok(( - RbSeries::new( + Obj::wrap(RbSeries::new( apply_lambda_with_bool_out_type(df, lambda, null_count, first_value) .into_series(), - ) - .into(), + )) + .as_value(), false, )); } else if out.is_kind_of(class::float()) { - let first_value = out.try_convert::().ok(); + let first_value = f64::try_convert(out).ok(); return Ok(( - RbSeries::new( + Obj::wrap(RbSeries::new( apply_lambda_with_primitive_out_type::( df, lambda, @@ -55,14 +55,14 @@ pub fn apply_lambda_unknown<'a>( first_value, ) .into_series(), - ) - .into(), + )) + .as_value(), false, )); } else if out.is_kind_of(class::integer()) { - let first_value = out.try_convert::().ok(); + let first_value = i64::try_convert(out).ok(); return Ok(( - RbSeries::new( + Obj::wrap(RbSeries::new( apply_lambda_with_primitive_out_type::( df, lambda, @@ -70,12 +70,12 @@ pub fn apply_lambda_unknown<'a>( first_value, ) .into_series(), - ) - .into(), + )) + .as_value(), false, )); // } else if out.is_kind_of(class::string()) { - // let first_value = out.try_convert::().ok(); + // let first_value = String::try_convert(out).ok(); // return Ok(( // RbSeries::new( // apply_lambda_with_utf8_out_type(df, lambda, null_count, first_value) @@ -85,25 +85,21 @@ pub fn apply_lambda_unknown<'a>( // false, // )); } else if out.respond_to("_s", true)? { - let rb_rbseries: Value = out.funcall("_s", ()).unwrap(); - let series = rb_rbseries - .try_convert::<&RbSeries>() - .unwrap() - .series - .borrow(); + let rb_rbseries: Obj = out.funcall("_s", ()).unwrap(); + let series = rb_rbseries.series.borrow(); let dt = series.dtype(); return Ok(( - RbSeries::new( + Obj::wrap(RbSeries::new( apply_lambda_with_list_out_type(df, lambda, null_count, Some(&series), dt)? .into_series(), - ) - .into(), + )) + .as_value(), false, )); - } else if out.try_convert::>>().is_ok() { - let first_value = out.try_convert::>>().unwrap().0; + } else if Wrap::>::try_convert(out).is_ok() { + let first_value = Wrap::>::try_convert(out).unwrap().0; return Ok(( - RbDataFrame::from( + Obj::wrap(RbDataFrame::from( apply_lambda_with_rows_output( df, lambda, @@ -112,8 +108,8 @@ pub fn apply_lambda_unknown<'a>( inference_size, ) .map_err(RbPolarsErr::from)?, - ) - .into(), + )) + .as_value(), true, )); } else if out.is_kind_of(class::array()) { @@ -143,7 +139,7 @@ where let iter = iters.iter_mut().map(|it| Wrap(it.next().unwrap())); let tpl = (RArray::from_iter(iter),); match lambda.funcall::<_, _, Value>("call", tpl) { - Ok(val) => val.try_convert::().ok(), + Ok(val) => T::try_convert(val).ok(), Err(e) => panic!("ruby function failed {}", e), } }) @@ -219,8 +215,7 @@ pub fn apply_lambda_with_list_out_type( let tpl = (RArray::from_iter(iter),); match lambda.funcall::<_, _, Value>("call", tpl) { Ok(val) => match val.funcall::<_, _, Value>("_s", ()) { - Ok(val) => val - .try_convert::<&RbSeries>() + Ok(val) => Obj::::try_convert(val) .ok() .map(|ps| ps.series.borrow().clone()), Err(_) => { @@ -257,11 +252,11 @@ pub fn apply_lambda_with_rows_output<'a>( let tpl = (RArray::from_iter(iter),); match lambda.funcall::<_, _, Value>("call", tpl) { Ok(val) => { - match val.try_convert::().ok() { + match RArray::try_convert(val).ok() { Some(tuple) => { row_buf.0.clear(); for v in tuple.each() { - let v = v.unwrap().try_convert::>().unwrap().0; + let v = Wrap::::try_convert(v.unwrap()).unwrap().0; row_buf.0.push(v); } let ptr = &row_buf as *const Row; diff --git a/ext/polars/src/apply/mod.rs b/ext/polars/src/apply/mod.rs index 07b02addce..af92007653 100644 --- a/ext/polars/src/apply/mod.rs +++ b/ext/polars/src/apply/mod.rs @@ -2,7 +2,7 @@ pub mod dataframe; pub mod lazy; pub mod series; -use magnus::{RHash, Value}; +use magnus::{prelude::*, RHash, Value}; use polars::chunked_array::builder::get_list_builder; use polars::prelude::*; use polars_core::export::rayon::prelude::*; @@ -68,7 +68,7 @@ fn iterator_to_struct( } } Some(dict) => { - let dict = dict.try_convert::()?; + let dict = RHash::try_convert(dict)?; if dict.len() != struct_width { return Err(crate::error::ComputeError::new_err( format!("Cannot create struct type.\n> The struct dtype expects {} fields, but it got a dict with {} fields.", struct_width, dict.len()) @@ -78,7 +78,7 @@ fn iterator_to_struct( // the first item determines the output name todo!() // for ((_, val), field_items) in dict.iter().zip(&mut items) { - // let item = val.try_convert::>()?; + // let item = Wrap::::try_convert(val)?; // field_items.push(item.0) // } } diff --git a/ext/polars/src/apply/series.rs b/ext/polars/src/apply/series.rs index 5be104425c..771e256644 100644 --- a/ext/polars/src/apply/series.rs +++ b/ext/polars/src/apply/series.rs @@ -1,4 +1,4 @@ -use magnus::{class, IntoValue, RHash, TryConvert, Value}; +use magnus::{class, prelude::*, typed_data::Obj, IntoValue, RHash, TryConvert, Value}; use polars::prelude::*; use super::*; @@ -14,12 +14,12 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>( null_count: usize, ) -> RbResult { if out.is_kind_of(class::true_class()) || out.is_kind_of(class::false_class()) { - let first_value = out.try_convert::().unwrap(); + let first_value = bool::try_convert(out).unwrap(); applyer .apply_lambda_with_bool_out_type(lambda, null_count, Some(first_value)) .map(|ca| ca.into_series().into()) } else if out.is_kind_of(class::float()) { - let first_value = out.try_convert::().unwrap(); + let first_value = f64::try_convert(out).unwrap(); applyer .apply_lambda_with_primitive_out_type::( lambda, @@ -28,7 +28,7 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>( ) .map(|ca| ca.into_series().into()) } else if out.is_kind_of(class::string()) { - let first_value = out.try_convert::().unwrap(); + let first_value = String::try_convert(out).unwrap(); applyer .apply_lambda_with_utf8_out_type(lambda, null_count, Some(first_value.as_str())) .map(|ca| ca.into_series().into()) @@ -37,13 +37,13 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>( } else if out.is_kind_of(class::array()) { todo!() } else if out.is_kind_of(class::hash()) { - let first = out.try_convert::>>()?; + let first = Wrap::>::try_convert(out)?; applyer.apply_to_struct(lambda, null_count, first.0) } // this succeeds for numpy ints as well, where checking if it is pyint fails // we do this later in the chain so that we don't extract integers from string chars. - else if out.try_convert::().is_ok() { - let first_value = out.try_convert::().unwrap(); + else if i64::try_convert(out).is_ok() { + let first_value = i64::try_convert(out).unwrap(); applyer .apply_lambda_with_primitive_out_type::( lambda, @@ -51,7 +51,7 @@ fn infer_and_finish<'a, A: ApplyLambda<'a>>( Some(first_value), ) .map(|ca| ca.into_series().into()) - } else if let Ok(av) = out.try_convert::>() { + } else if let Ok(av) = Wrap::::try_convert(out) { applyer .apply_extract_any_values(lambda, null_count, av.0) .map(|s| s.into()) @@ -141,7 +141,7 @@ where S: TryConvert, { match call_lambda(lambda, in_val) { - Ok(out) => out.try_convert::(), + Ok(out) => S::try_convert(out), Err(e) => panic!("ruby function failed {}", e), } } @@ -151,13 +151,9 @@ where T: IntoValue, { let out: Value = lambda.funcall("call", (in_val,))?; - let py_series: Value = out.funcall("_s", ())?; - Ok(py_series - .try_convert::<&RbSeries>() - .unwrap() - .series - .borrow() - .clone()) + let py_series: Obj = out.funcall("_s", ())?; + let tmp = py_series.series.borrow(); + Ok(tmp.clone()) } impl<'a> ApplyLambda<'a> for BooleanChunked { diff --git a/ext/polars/src/batched_csv.rs b/ext/polars/src/batched_csv.rs index eabcf61134..4fcb963ecc 100644 --- a/ext/polars/src/batched_csv.rs +++ b/ext/polars/src/batched_csv.rs @@ -1,4 +1,4 @@ -use magnus::{RArray, Value}; +use magnus::{prelude::*, RArray, Value}; use polars::io::mmap::MmapBytesReader; use polars::io::RowCount; use polars::prelude::read_impl::OwnedBatchedCsvReader; @@ -24,31 +24,31 @@ impl RbBatchedCsv { pub fn new(arguments: &[Value]) -> RbResult { // start arguments // this pattern is needed for more than 16 - let infer_schema_length: Option = arguments[0].try_convert()?; - let chunk_size: usize = arguments[1].try_convert()?; - let has_header: bool = arguments[2].try_convert()?; - let ignore_errors: bool = arguments[3].try_convert()?; - let n_rows: Option = arguments[4].try_convert()?; - let skip_rows: usize = arguments[5].try_convert()?; - let projection: Option> = arguments[6].try_convert()?; - let sep: String = arguments[7].try_convert()?; - let rechunk: bool = arguments[8].try_convert()?; - let columns: Option> = arguments[9].try_convert()?; - let encoding: Wrap = arguments[10].try_convert()?; - let n_threads: Option = arguments[11].try_convert()?; - let path: PathBuf = arguments[12].try_convert()?; - let overwrite_dtype: Option)>> = arguments[13].try_convert()?; + let infer_schema_length = Option::::try_convert(arguments[0])?; + let chunk_size = usize::try_convert(arguments[1])?; + let has_header = bool::try_convert(arguments[2])?; + let ignore_errors = bool::try_convert(arguments[3])?; + let n_rows = Option::::try_convert(arguments[4])?; + let skip_rows = usize::try_convert(arguments[5])?; + let projection = Option::>::try_convert(arguments[6])?; + let sep = String::try_convert(arguments[7])?; + let rechunk = bool::try_convert(arguments[8])?; + let columns = Option::>::try_convert(arguments[9])?; + let encoding = Wrap::::try_convert(arguments[10])?; + let n_threads = Option::::try_convert(arguments[11])?; + let path = PathBuf::try_convert(arguments[12])?; + let overwrite_dtype = Option::)>>::try_convert(arguments[13])?; // TODO fix - let overwrite_dtype_slice: Option>> = None; // arguments[14].try_convert()?; - let low_memory: bool = arguments[15].try_convert()?; - let comment_char: Option = arguments[16].try_convert()?; - let quote_char: Option = arguments[17].try_convert()?; - let null_values: Option> = arguments[18].try_convert()?; - let try_parse_dates: bool = arguments[19].try_convert()?; - let skip_rows_after_header: usize = arguments[20].try_convert()?; - let row_count: Option<(String, IdxSize)> = arguments[21].try_convert()?; - let sample_size: usize = arguments[22].try_convert()?; - let eol_char: String = arguments[23].try_convert()?; + let overwrite_dtype_slice = Option::>>::None; // Option::>>::try_convert(arguments[14])?; + let low_memory = bool::try_convert(arguments[15])?; + let comment_char = Option::::try_convert(arguments[16])?; + let quote_char = Option::::try_convert(arguments[17])?; + let null_values = Option::>::try_convert(arguments[18])?; + let try_parse_dates = bool::try_convert(arguments[19])?; + let skip_rows_after_header = usize::try_convert(arguments[20])?; + let row_count = Option::<(String, IdxSize)>::try_convert(arguments[21])?; + let sample_size = usize::try_convert(arguments[22])?; + let eol_char = String::try_convert(arguments[23])?; // end arguments let null_values = null_values.map(|w| w.0); diff --git a/ext/polars/src/conversion.rs b/ext/polars/src/conversion.rs index 04d439e732..250b7d9c81 100644 --- a/ext/polars/src/conversion.rs +++ b/ext/polars/src/conversion.rs @@ -1,10 +1,10 @@ -use std::fmt::{Display, Formatter}; +use std::fmt::{Debug, Display, Formatter}; use std::hash::{Hash, Hasher}; use magnus::encoding::{EncodingCapable, Index}; use magnus::{ - class, exception, r_hash::ForEach, ruby_handle::RubyHandle, Float, Integer, IntoValue, Module, - RArray, RHash, RString, Symbol, TryConvert, Value, QNIL, + class, exception, prelude::*, r_hash::ForEach, value::Opaque, Float, Integer, IntoValue, + Module, RArray, RHash, RString, Ruby, Symbol, TryConvert, Value, }; use polars::chunked_array::object::PolarsObjectSafe; use polars::chunked_array::ops::{FillNullLimit, FillNullStrategy}; @@ -57,7 +57,7 @@ impl From for Wrap { } pub(crate) fn get_rbseq(obj: Value) -> RbResult<(RArray, usize)> { - let seq: RArray = obj.try_convert()?; + let seq = RArray::try_convert(obj)?; let len = seq.len(); Ok((seq, len)) } @@ -84,7 +84,7 @@ impl TryConvert for Wrap { for res in seq.each() { let item = res?; - match item.try_convert::() { + match String::try_convert(item) { Ok(val) => builder.append_value(&val), Err(_) => builder.append_null(), } @@ -100,7 +100,7 @@ impl TryConvert for Wrap { for res in seq.each() { let item = res?; - match item.try_convert::() { + match RString::try_convert(item) { Ok(val) => builder.append_value(unsafe { val.as_slice() }), Err(_) => builder.append_null(), } @@ -111,11 +111,11 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - if let Ok(s) = ob.try_convert::() { + if let Ok(s) = String::try_convert(ob) { Ok(Wrap(NullValues::AllColumnsSingle(s))) - } else if let Ok(s) = ob.try_convert::>() { + } else if let Ok(s) = Vec::::try_convert(ob) { Ok(Wrap(NullValues::AllColumns(s))) - } else if let Ok(s) = ob.try_convert::>() { + } else if let Ok(s) = Vec::<(String, String)>::try_convert(ob) { Ok(Wrap(NullValues::Named(s))) } else { Err(RbPolarsErr::other( @@ -134,22 +134,22 @@ fn struct_dict<'a>(vals: impl Iterator>, flds: &[Field]) -> } impl IntoValue for Wrap> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, ruby: &Ruby) -> Value { match self.0 { - AnyValue::UInt8(v) => Value::from(v), - AnyValue::UInt16(v) => Value::from(v), - AnyValue::UInt32(v) => Value::from(v), - AnyValue::UInt64(v) => Value::from(v), - AnyValue::Int8(v) => Value::from(v), - AnyValue::Int16(v) => Value::from(v), - AnyValue::Int32(v) => Value::from(v), - AnyValue::Int64(v) => Value::from(v), - AnyValue::Float32(v) => Value::from(v), - AnyValue::Float64(v) => Value::from(v), - AnyValue::Null => *QNIL, - AnyValue::Boolean(v) => Value::from(v), - AnyValue::Utf8(v) => Value::from(v), - AnyValue::Utf8Owned(v) => Value::from(v.as_str()), + AnyValue::UInt8(v) => ruby.into_value(v), + AnyValue::UInt16(v) => ruby.into_value(v), + AnyValue::UInt32(v) => ruby.into_value(v), + AnyValue::UInt64(v) => ruby.into_value(v), + AnyValue::Int8(v) => ruby.into_value(v), + AnyValue::Int16(v) => ruby.into_value(v), + AnyValue::Int32(v) => ruby.into_value(v), + AnyValue::Int64(v) => ruby.into_value(v), + AnyValue::Float32(v) => ruby.into_value(v), + AnyValue::Float64(v) => ruby.into_value(v), + AnyValue::Null => ruby.qnil().as_value(), + AnyValue::Boolean(v) => ruby.into_value(v), + AnyValue::Utf8(v) => ruby.into_value(v), + AnyValue::Utf8Owned(v) => ruby.into_value(v.as_str()), AnyValue::Categorical(idx, rev, arr) => { let s = if arr.is_null() { rev.get(idx) @@ -177,11 +177,11 @@ impl IntoValue for Wrap> { AnyValue::StructOwned(payload) => struct_dict(payload.0.into_iter(), &payload.1), AnyValue::Object(v) => { let object = v.as_any().downcast_ref::().unwrap(); - object.inner + object.to_object() } AnyValue::ObjectOwned(v) => { let object = v.0.as_any().downcast_ref::().unwrap(); - object.inner + object.to_object() } AnyValue::Binary(v) => RString::from_slice(v).into_value(), AnyValue::BinaryOwned(v) => RString::from_slice(&v).into_value(), @@ -193,7 +193,7 @@ impl IntoValue for Wrap> { } impl IntoValue for Wrap { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let pl = crate::rb_modules::polars(); match self.0 { @@ -266,7 +266,7 @@ impl IntoValue for Wrap { } impl IntoValue for Wrap { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let tu = match self.0 { TimeUnit::Nanoseconds => "ns", TimeUnit::Microseconds => "us", @@ -277,14 +277,14 @@ impl IntoValue for Wrap { } impl IntoValue for Wrap<&Utf8Chunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let iter = self.0.into_iter(); RArray::from_iter(iter).into_value() } } impl IntoValue for Wrap<&BinaryChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let iter = self .0 .into_iter() @@ -294,7 +294,7 @@ impl IntoValue for Wrap<&BinaryChunked> { } impl IntoValue for Wrap<&StructChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let s = self.0.clone().into_series(); // todo! iterate its chunks and flatten. // make series::iter() accept a chunk index. @@ -312,7 +312,7 @@ impl IntoValue for Wrap<&StructChunked> { } impl IntoValue for Wrap<&DurationChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let utils = utils(); let time_unit = Wrap(self.0.time_unit()).into_value(); let iter = self.0.into_iter().map(|opt_v| { @@ -327,7 +327,7 @@ impl IntoValue for Wrap<&DurationChunked> { } impl IntoValue for Wrap<&DatetimeChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let utils = utils(); let time_unit = Wrap(self.0.time_unit()).into_value(); let time_zone = self.0.time_zone().clone().into_value(); @@ -343,7 +343,7 @@ impl IntoValue for Wrap<&DatetimeChunked> { } impl IntoValue for Wrap<&TimeChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let utils = utils(); let iter = self.0.into_iter().map(|opt_v| { opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_time", (v,)).unwrap()) @@ -353,7 +353,7 @@ impl IntoValue for Wrap<&TimeChunked> { } impl IntoValue for Wrap<&DateChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let utils = utils(); let iter = self.0.into_iter().map(|opt_v| { opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_date", (v,)).unwrap()) @@ -363,7 +363,7 @@ impl IntoValue for Wrap<&DateChunked> { } impl IntoValue for Wrap<&DecimalChunked> { - fn into_value_with(self, _: &RubyHandle) -> Value { + fn into_value_with(self, _: &Ruby) -> Value { let utils = utils(); let rb_scale = (-(self.0.scale() as i32)).into_value(); let iter = self.0.into_iter().map(|opt_v| { @@ -427,36 +427,35 @@ impl TryConvert for Wrap { } } // TODO improve - } else if ob.try_convert::().is_err() { + } else if String::try_convert(ob).is_err() { let name = unsafe { ob.class().name() }.into_owned(); match name.as_str() { "Polars::Duration" => { let time_unit: Value = ob.funcall("time_unit", ()).unwrap(); - let time_unit = time_unit.try_convert::>()?.0; + let time_unit = Wrap::::try_convert(time_unit)?.0; DataType::Duration(time_unit) } "Polars::Datetime" => { let time_unit: Value = ob.funcall("time_unit", ()).unwrap(); - let time_unit = time_unit.try_convert::>()?.0; - let time_zone: Value = ob.funcall("time_zone", ()).unwrap(); - let time_zone = time_zone.try_convert()?; + let time_unit = Wrap::::try_convert(time_unit)?.0; + let time_zone = ob.funcall("time_zone", ())?; DataType::Datetime(time_unit, time_zone) } "Polars::Decimal" => { - let precision = ob.funcall::<_, _, Value>("precision", ())?.try_convert()?; - let scale = ob.funcall::<_, _, Value>("scale", ())?.try_convert()?; + let precision = ob.funcall("precision", ())?; + let scale = ob.funcall("scale", ())?; DataType::Decimal(precision, Some(scale)) } "Polars::List" => { let inner: Value = ob.funcall("inner", ()).unwrap(); - let inner = inner.try_convert::>()?; + let inner = Wrap::::try_convert(inner)?; DataType::List(Box::new(inner.0)) } "Polars::Struct" => { let arr: RArray = ob.funcall("fields", ())?; let mut fields = Vec::with_capacity(arr.len()); for v in arr.each() { - fields.push(v?.try_convert::>()?.0); + fields.push(Wrap::::try_convert(v?)?.0); } DataType::Struct(fields) } @@ -468,7 +467,7 @@ impl TryConvert for Wrap { } } } else { - match ob.try_convert::()?.as_str() { + match String::try_convert(ob)?.as_str() { "u8" => DataType::UInt8, "u16" => DataType::UInt16, "u32" => DataType::UInt32, @@ -506,7 +505,7 @@ impl TryConvert for Wrap { impl<'s> TryConvert for Wrap> { fn try_convert(ob: Value) -> RbResult { if ob.is_kind_of(class::true_class()) || ob.is_kind_of(class::false_class()) { - Ok(AnyValue::Boolean(ob.try_convert::()?).into()) + Ok(AnyValue::Boolean(bool::try_convert(ob)?).into()) } else if let Some(v) = Integer::from_value(ob) { Ok(AnyValue::Int64(v.to_i64()?).into()) } else if let Some(v) = Float::from_value(ob) { @@ -532,8 +531,8 @@ impl<'s> TryConvert for Wrap> { let mut keys = Vec::with_capacity(len); let mut vals = Vec::with_capacity(len); dict.foreach(|k: Value, v: Value| { - let key = k.try_convert::()?; - let val = v.try_convert::>()?.0; + let key = String::try_convert(k)?; + let val = Wrap::::try_convert(v)?.0; let dtype = DataType::from(&val); keys.push(Field::new(&key, dtype)); vals.push(val); @@ -550,7 +549,7 @@ impl<'s> TryConvert for Wrap> { let mut iter = list.each(); for item in (&mut iter).take(25) { - avs.push(item?.try_convert::>()?.0) + avs.push(Wrap::::try_convert(item?)?.0) } let (dtype, _n_types) = any_values_to_dtype(&avs).map_err(RbPolarsErr::from)?; @@ -558,7 +557,7 @@ impl<'s> TryConvert for Wrap> { // push the rest avs.reserve(list.len()); for item in iter { - avs.push(item?.try_convert::>()?.0) + avs.push(Wrap::::try_convert(item?)?.0) } let s = Series::from_any_values_and_dtype("", &avs, &dtype, true) @@ -581,11 +580,7 @@ impl<'s> TryConvert for Wrap> { .funcall::<_, _, i64>("to_i", ())?; Ok(Wrap(AnyValue::Date((v / 86400) as i32))) } else if ob.is_kind_of(crate::rb_modules::bigdecimal()) { - let (sign, digits, _, exp): (i8, String, i32, i32) = ob - .funcall::<_, _, Value>("split", ()) - .unwrap() - .try_convert() - .unwrap(); + let (sign, digits, _, exp): (i8, String, i32, i32) = ob.funcall("split", ()).unwrap(); let (mut v, scale) = abs_decimal_from_digits(digits, exp).ok_or_else(|| { RbPolarsErr::other("BigDecimal is too large to fit in Decimal128".into()) })?; @@ -606,8 +601,8 @@ impl<'s> TryConvert for Wrap> { impl<'s> TryConvert for Wrap> { fn try_convert(ob: Value) -> RbResult { let mut vals: Vec>> = Vec::new(); - for item in ob.try_convert::()?.each() { - vals.push(item?.try_convert::>>()?); + for item in RArray::try_convert(ob)?.each() { + vals.push(Wrap::>::try_convert(item?)?); } let vals: Vec = unsafe { std::mem::transmute(vals) }; Ok(Wrap(Row(vals))) @@ -616,7 +611,7 @@ impl<'s> TryConvert for Wrap> { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let dict = ob.try_convert::()?; + let dict = RHash::try_convert(ob)?; let mut schema = Vec::new(); dict.foreach(|key: String, val: Wrap| { @@ -629,15 +624,23 @@ impl TryConvert for Wrap { } } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct ObjectValue { - pub inner: Value, + pub inner: Opaque, +} + +impl Debug for ObjectValue { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ObjectValue") + .field("inner", &self.to_object()) + .finish() + } } impl Hash for ObjectValue { fn hash(&self, state: &mut H) { let h = self - .inner + .to_object() .funcall::<_, _, isize>("hash", ()) .expect("should be hashable"); state.write_isize(h) @@ -648,13 +651,13 @@ impl Eq for ObjectValue {} impl PartialEq for ObjectValue { fn eq(&self, other: &Self) -> bool { - self.inner.eql(&other.inner).unwrap_or(false) + self.to_object().eql(other.to_object()).unwrap_or(false) } } impl Display for ObjectValue { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.inner) + write!(f, "{}", self.to_object()) } } @@ -666,13 +669,13 @@ impl PolarsObject for ObjectValue { impl From for ObjectValue { fn from(v: Value) -> Self { - Self { inner: v } + Self { inner: v.into() } } } impl TryConvert for ObjectValue { fn try_convert(ob: Value) -> RbResult { - Ok(ObjectValue { inner: ob }) + Ok(ObjectValue { inner: ob.into() }) } } @@ -685,19 +688,21 @@ impl From<&dyn PolarsObjectSafe> for &ObjectValue { // TODO remove impl ObjectValue { pub fn to_object(&self) -> Value { - self.inner + Ruby::get().unwrap().get_inner(self.inner) } } impl IntoValue for ObjectValue { - fn into_value_with(self, _: &RubyHandle) -> Value { - self.inner + fn into_value_with(self, _: &Ruby) -> Value { + self.to_object() } } impl Default for ObjectValue { fn default() -> Self { - ObjectValue { inner: *QNIL } + ObjectValue { + inner: Ruby::get().unwrap().qnil().as_value().into(), + } } } @@ -710,13 +715,13 @@ pub(crate) fn dicts_to_rows( let mut key_names = PlIndexSet::new(); for d in dicts.each().take(infer_schema_len) { let d = d?; - let d = d.try_convert::()?; + let d = RHash::try_convert(d)?; d.foreach(|name: Value, _value: Value| { if let Some(v) = Symbol::from_value(name) { key_names.insert(v.name()?.into()); } else { - key_names.insert(name.try_convert::()?); + key_names.insert(String::try_convert(name)?); }; Ok(ForEach::Continue) })?; @@ -726,7 +731,7 @@ pub(crate) fn dicts_to_rows( for d in dicts.each() { let d = d?; - let d = d.try_convert::()?; + let d = RHash::try_convert(d)?; let mut row = Vec::with_capacity(key_names.len()); @@ -734,7 +739,7 @@ pub(crate) fn dicts_to_rows( // TODO improve performance let val = match d.get(k.clone()).or_else(|| d.get(Symbol::new(k))) { None => AnyValue::Null, - Some(val) => val.try_convert::>()?.0, + Some(val) => Wrap::::try_convert(val)?.0, }; row.push(val) } @@ -745,7 +750,7 @@ pub(crate) fn dicts_to_rows( impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "backward" => AsofStrategy::Backward, "forward" => AsofStrategy::Forward, v => { @@ -761,7 +766,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "linear" => InterpolationMethod::Linear, "nearest" => InterpolationMethod::Nearest, v => { @@ -776,7 +781,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap> { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "uncompressed" => None, "snappy" => Some(AvroCompression::Snappy), "deflate" => Some(AvroCompression::Deflate), @@ -793,7 +798,7 @@ impl TryConvert for Wrap> { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "physical" => CategoricalOrdering::Physical, "lexical" => CategoricalOrdering::Lexical, v => { @@ -809,7 +814,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "window" => StartBy::WindowBound, "datapoint" => StartBy::DataPoint, "monday" => StartBy::Monday, @@ -825,7 +830,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "left" => ClosedWindow::Left, "right" => ClosedWindow::Right, "both" => ClosedWindow::Both, @@ -843,7 +848,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "utf8" => CsvEncoding::Utf8, "utf8-lossy" => CsvEncoding::LossyUtf8, v => { @@ -859,7 +864,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap> { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "uncompressed" => None, "lz4" => Some(IpcCompression::LZ4), "zstd" => Some(IpcCompression::ZSTD), @@ -876,7 +881,7 @@ impl TryConvert for Wrap> { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "inner" => JoinType::Inner, "left" => JoinType::Left, "outer" => JoinType::Outer, @@ -897,7 +902,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "first_non_null" => ListToStructWidthStrategy::FirstNonNull, "max_width" => ListToStructWidthStrategy::MaxWidth, v => { @@ -913,7 +918,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "drop" => NullBehavior::Drop, "ignore" => NullBehavior::Ignore, v => { @@ -929,7 +934,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "ignore" => NullStrategy::Ignore, "propagate" => NullStrategy::Propagate, v => { @@ -945,7 +950,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "auto" => ParallelStrategy::Auto, "columns" => ParallelStrategy::Columns, "row_groups" => ParallelStrategy::RowGroups, @@ -963,7 +968,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "lower" => QuantileInterpolOptions::Lower, "higher" => QuantileInterpolOptions::Higher, "nearest" => QuantileInterpolOptions::Nearest, @@ -982,7 +987,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "min" => RankMethod::Min, "max" => RankMethod::Max, "average" => RankMethod::Average, @@ -1002,7 +1007,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "ns" => TimeUnit::Nanoseconds, "us" => TimeUnit::Microseconds, "ms" => TimeUnit::Milliseconds, @@ -1019,7 +1024,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "first" => UniqueKeepStrategy::First, "last" => UniqueKeepStrategy::Last, v => { @@ -1035,7 +1040,7 @@ impl TryConvert for Wrap { impl TryConvert for Wrap { fn try_convert(ob: Value) -> RbResult { - let parsed = match ob.try_convert::()?.as_str() { + let parsed = match String::try_convert(ob)?.as_str() { "any" => SearchSortedSide::Any, "left" => SearchSortedSide::Left, "right" => SearchSortedSide::Right, diff --git a/ext/polars/src/dataframe.rs b/ext/polars/src/dataframe.rs index c9ebb51fa0..9f3c0f829f 100644 --- a/ext/polars/src/dataframe.rs +++ b/ext/polars/src/dataframe.rs @@ -1,4 +1,6 @@ -use magnus::{r_hash::ForEach, IntoValue, RArray, RHash, RString, Value}; +use magnus::{ + prelude::*, r_hash::ForEach, typed_data::Obj, IntoValue, RArray, RHash, RString, Value, +}; use polars::frame::row::{rows_to_schema_supertypes, Row}; use polars::frame::NullStrategy; use polars::io::avro::AvroCompression; @@ -86,7 +88,7 @@ impl RbDataFrame { pub fn init(columns: RArray) -> RbResult { let mut cols = Vec::new(); for i in columns.each() { - cols.push(i?.try_convert::<&RbSeries>()?.series.borrow().clone()); + cols.push(<&RbSeries>::try_convert(i?)?.series.borrow().clone()); } let df = DataFrame::new(cols).map_err(RbPolarsErr::from)?; Ok(RbDataFrame::new(df)) @@ -99,32 +101,32 @@ impl RbDataFrame { pub fn read_csv(arguments: &[Value]) -> RbResult { // start arguments // this pattern is needed for more than 16 - let rb_f: Value = arguments[0].try_convert()?; - let infer_schema_length: Option = arguments[1].try_convert()?; - let chunk_size: usize = arguments[2].try_convert()?; - let has_header: bool = arguments[3].try_convert()?; - let ignore_errors: bool = arguments[4].try_convert()?; - let n_rows: Option = arguments[5].try_convert()?; - let skip_rows: usize = arguments[6].try_convert()?; - let projection: Option> = arguments[7].try_convert()?; - let sep: String = arguments[8].try_convert()?; - let rechunk: bool = arguments[9].try_convert()?; - let columns: Option> = arguments[10].try_convert()?; - let encoding: Wrap = arguments[11].try_convert()?; - let n_threads: Option = arguments[12].try_convert()?; - let path: Option = arguments[13].try_convert()?; - let overwrite_dtype: Option)>> = arguments[14].try_convert()?; + let rb_f = arguments[0]; + let infer_schema_length = Option::::try_convert(arguments[1])?; + let chunk_size = usize::try_convert(arguments[2])?; + let has_header = bool::try_convert(arguments[3])?; + let ignore_errors = bool::try_convert(arguments[4])?; + let n_rows = Option::::try_convert(arguments[5])?; + let skip_rows = usize::try_convert(arguments[6])?; + let projection = Option::>::try_convert(arguments[7])?; + let sep = String::try_convert(arguments[8])?; + let rechunk = bool::try_convert(arguments[9])?; + let columns = Option::>::try_convert(arguments[10])?; + let encoding = Wrap::::try_convert(arguments[11])?; + let n_threads = Option::::try_convert(arguments[12])?; + let path = Option::::try_convert(arguments[13])?; + let overwrite_dtype = Option::)>>::try_convert(arguments[14])?; // TODO fix - let overwrite_dtype_slice: Option>> = None; // arguments[15].try_convert()?; - let low_memory: bool = arguments[16].try_convert()?; - let comment_char: Option = arguments[17].try_convert()?; - let quote_char: Option = arguments[18].try_convert()?; - let null_values: Option> = arguments[19].try_convert()?; - let try_parse_dates: bool = arguments[20].try_convert()?; - let skip_rows_after_header: usize = arguments[21].try_convert()?; - let row_count: Option<(String, IdxSize)> = arguments[22].try_convert()?; - let sample_size: usize = arguments[23].try_convert()?; - let eol_char: String = arguments[24].try_convert()?; + let overwrite_dtype_slice = Option::>>::None; // Option::>>::try_convert(arguments[15])?; + let low_memory = bool::try_convert(arguments[16])?; + let comment_char = Option::::try_convert(arguments[17])?; + let quote_char = Option::::try_convert(arguments[18])?; + let null_values = Option::>::try_convert(arguments[19])?; + let try_parse_dates = bool::try_convert(arguments[20])?; + let skip_rows_after_header = usize::try_convert(arguments[21])?; + let row_count = Option::<(String, IdxSize)>::try_convert(arguments[22])?; + let sample_size = usize::try_convert(arguments[23])?; + let eol_char = String::try_convert(arguments[24])?; // end arguments let null_values = null_values.map(|w| w.0); @@ -265,7 +267,7 @@ impl RbDataFrame { ) -> RbResult<()> { use polars::io::avro::AvroWriter; - if let Ok(s) = rb_f.try_convert::() { + if let Ok(s) = String::try_convert(rb_f) { let f = std::fs::File::create(s).unwrap(); AvroWriter::new(f) .with_compression(compression.0) @@ -407,7 +409,7 @@ impl RbDataFrame { ) -> RbResult<()> { let null = null_value.unwrap_or_default(); - if let Ok(s) = rb_f.try_convert::() { + if let Ok(s) = String::try_convert(rb_f) { let f = std::fs::File::create(s).unwrap(); // no need for a buffered writer, because the csv writer does internal buffering CsvWriter::new(f) @@ -449,7 +451,7 @@ impl RbDataFrame { rb_f: Value, compression: Wrap>, ) -> RbResult<()> { - if let Ok(s) = rb_f.try_convert::() { + if let Ok(s) = String::try_convert(rb_f) { let f = std::fs::File::create(s).unwrap(); IpcWriter::new(f) .with_compression(compression.0) @@ -487,7 +489,7 @@ impl RbDataFrame { _ => Wrap(s.get(idx).unwrap()).into_value(), }), ) - .into() + .as_value() } pub fn row_tuples(&self) -> Value { @@ -507,7 +509,7 @@ impl RbDataFrame { }), ) })) - .into() + .as_value() } pub fn to_numo(&self) -> Option { @@ -537,7 +539,7 @@ impl RbDataFrame { ) -> RbResult<()> { let compression = parse_parquet_compression(&compression, compression_level)?; - if let Ok(s) = rb_f.try_convert::() { + if let Ok(s) = String::try_convert(rb_f) { let f = std::fs::File::create(s).unwrap(); ParquetWriter::new(f) .with_compression(compression) @@ -1088,7 +1090,7 @@ impl RbDataFrame { _ => return apply_lambda_unknown(df, lambda, inference_size), }; - Ok((RbSeries::from(out).into(), false)) + Ok((Obj::wrap(RbSeries::from(out)).as_value(), false)) } pub fn shrink_to_fit(&self) { diff --git a/ext/polars/src/expr.rs b/ext/polars/src/expr.rs index a173764d51..4a0daa5687 100644 --- a/ext/polars/src/expr.rs +++ b/ext/polars/src/expr.rs @@ -8,7 +8,7 @@ mod meta; mod string; mod r#struct; -use magnus::RArray; +use magnus::{prelude::*, RArray}; use polars::lazy::dsl::Expr; use crate::RbResult; @@ -28,7 +28,7 @@ impl From for RbExpr { pub fn rb_exprs_to_exprs(rb_exprs: RArray) -> RbResult> { let mut exprs = Vec::new(); for item in rb_exprs.each() { - exprs.push(item?.try_convert::<&RbExpr>()?.inner.clone()); + exprs.push(<&RbExpr>::try_convert(item?)?.inner.clone()); } Ok(exprs) } diff --git a/ext/polars/src/expr/general.rs b/ext/polars/src/expr/general.rs index 425f212d4b..664afd5b9c 100644 --- a/ext/polars/src/expr/general.rs +++ b/ext/polars/src/expr/general.rs @@ -1,4 +1,4 @@ -use magnus::{block::Proc, IntoValue, RArray, Value}; +use magnus::{block::Proc, prelude::*, value::Opaque, IntoValue, RArray, Ruby, Value}; use polars::lazy::dsl; use polars::prelude::*; use polars::series::ops::NullBehavior; @@ -388,18 +388,18 @@ impl RbExpr { } pub fn clip(&self, min: Value, max: Value) -> Self { - let min = min.try_convert::>().unwrap().0; - let max = max.try_convert::>().unwrap().0; + let min = Wrap::::try_convert(min).unwrap().0; + let max = Wrap::::try_convert(max).unwrap().0; self.clone().inner.clip(min, max).into() } pub fn clip_min(&self, min: Value) -> Self { - let min = min.try_convert::>().unwrap().0; + let min = Wrap::::try_convert(min).unwrap().0; self.clone().inner.clip_min(min).into() } pub fn clip_max(&self, max: Value) -> Self { - let max = max.try_convert::>().unwrap().0; + let max = Wrap::::try_convert(max).unwrap().0; self.clone().inner.clip_max(max).into() } @@ -554,9 +554,11 @@ impl RbExpr { } pub fn map_alias(&self, lambda: Proc) -> Self { + let lambda = Opaque::from(lambda); self.inner .clone() .map_alias(move |name| { + let lambda = Ruby::get().unwrap().get_inner(lambda); let out = lambda.call::<_, String>((name,)); match out { Ok(out) => Ok(out), @@ -915,11 +917,13 @@ impl RbExpr { pub fn extend_constant(&self, value: Wrap, n: usize) -> Self { let value = value.into_value(); + let value = Opaque::from(value); self.inner .clone() .apply( move |s| { - let value = value.try_convert::>().unwrap().0; + let value = Ruby::get().unwrap().get_inner(value); + let value = Wrap::::try_convert(value).unwrap().0; s.extend_constant(value, n).map(Some) }, GetOutput::same_type(), diff --git a/ext/polars/src/expr/list.rs b/ext/polars/src/expr/list.rs index 7c7b6945dd..42619be381 100644 --- a/ext/polars/src/expr/list.rs +++ b/ext/polars/src/expr/list.rs @@ -127,7 +127,7 @@ impl RbExpr { // let name_gen = name_gen.map(|lambda| { // Arc::new(move |idx: usize| { // let out: Value = lambda.funcall("call", (idx,)).unwrap(); - // out.try_convert::().unwrap() + // String::try_convert(out).unwrap() // }) as NameGenerator // }); diff --git a/ext/polars/src/file.rs b/ext/polars/src/file.rs index e806d39c34..d22543e8ab 100644 --- a/ext/polars/src/file.rs +++ b/ext/polars/src/file.rs @@ -1,4 +1,4 @@ -use magnus::{exception, Error, RString, Value}; +use magnus::{exception, prelude::*, Error, RString, Value}; use polars::io::mmap::MmapBytesReader; use std::fs::File; use std::io::Cursor; @@ -7,7 +7,7 @@ use std::path::PathBuf; use crate::RbResult; pub fn get_file_like(f: Value, truncate: bool) -> RbResult { - let str_slice = f.try_convert::()?; + let str_slice = PathBuf::try_convert(f)?; let f = if truncate { File::create(str_slice) .map_err(|e| Error::new(exception::runtime_error(), e.to_string()))? @@ -23,7 +23,7 @@ pub fn get_mmap_bytes_reader(rb_f: Value) -> RbResult> // TODO avoid copy Ok(Box::new(Cursor::new(bytes.to_vec()))) } else { - let p = rb_f.try_convert::()?; + let p = PathBuf::try_convert(rb_f)?; let f = File::open(p).map_err(|e| Error::new(exception::runtime_error(), e.to_string()))?; Ok(Box::new(f)) } diff --git a/ext/polars/src/functions/io.rs b/ext/polars/src/functions/io.rs index b46018f2f5..e76b565865 100644 --- a/ext/polars/src/functions/io.rs +++ b/ext/polars/src/functions/io.rs @@ -5,7 +5,7 @@ use crate::file::get_file_like; use crate::prelude::DataType; use crate::{RbPolarsErr, RbResult}; -pub fn read_ipc_schema(rb_f: Value) -> RbResult { +pub fn read_ipc_schema(rb_f: Value) -> RbResult { use polars_core::export::arrow::io::ipc::read::read_file_metadata; let mut r = get_file_like(rb_f, false)?; let metadata = read_file_metadata(&mut r).map_err(RbPolarsErr::arrow)?; @@ -15,10 +15,10 @@ pub fn read_ipc_schema(rb_f: Value) -> RbResult { let dt: Wrap = Wrap((&field.data_type).into()); dict.aset(field.name, dt)?; } - Ok(dict.into()) + Ok(dict) } -pub fn read_parquet_schema(rb_f: Value) -> RbResult { +pub fn read_parquet_schema(rb_f: Value) -> RbResult { use polars_core::export::arrow::io::parquet::read::{infer_schema, read_metadata}; let mut r = get_file_like(rb_f, false)?; @@ -30,5 +30,5 @@ pub fn read_parquet_schema(rb_f: Value) -> RbResult { let dt: Wrap = Wrap((&field.data_type).into()); dict.aset(field.name, dt)?; } - Ok(dict.into()) + Ok(dict) } diff --git a/ext/polars/src/functions/lazy.rs b/ext/polars/src/functions/lazy.rs index f982272556..a32a06b697 100644 --- a/ext/polars/src/functions/lazy.rs +++ b/ext/polars/src/functions/lazy.rs @@ -1,5 +1,7 @@ use magnus::encoding::{self, EncodingCapable}; -use magnus::{class, Float, Integer, RArray, RString, Value}; +use magnus::{ + class, prelude::*, typed_data::Obj, value::Opaque, Float, Integer, RArray, RString, Ruby, Value, +}; use polars::lazy::dsl; use polars::prelude::*; @@ -45,7 +47,7 @@ pub fn col(name: String) -> RbExpr { pub fn collect_all(lfs: RArray) -> RbResult { let lfs = lfs .each() - .map(|v| v?.try_convert::<&RbLazyFrame>()) + .map(|v| <&RbLazyFrame>::try_convert(v?)) .collect::>>()?; Ok(RArray::from_iter(lfs.iter().map(|lf| { @@ -137,23 +139,27 @@ pub fn dtype_cols(dtypes: Vec) -> RbExpr { pub fn fold(acc: &RbExpr, lambda: Value, exprs: RArray) -> RbResult { let exprs = rb_exprs_to_exprs(exprs)?; + let lambda = Opaque::from(lambda); - let func = move |a: Series, b: Series| binary_lambda(lambda, a, b); + let func = + move |a: Series, b: Series| binary_lambda(Ruby::get().unwrap().get_inner(lambda), a, b); Ok(polars::lazy::dsl::fold_exprs(acc.inner.clone(), func, exprs).into()) } pub fn cumfold(acc: &RbExpr, lambda: Value, exprs: RArray, include_init: bool) -> RbResult { let exprs = rb_exprs_to_exprs(exprs)?; + let lambda = Opaque::from(lambda); - let func = move |a: Series, b: Series| binary_lambda(lambda, a, b); + let func = + move |a: Series, b: Series| binary_lambda(Ruby::get().unwrap().get_inner(lambda), a, b); Ok(polars::lazy::dsl::cumfold_exprs(acc.inner.clone(), func, exprs, include_init).into()) } pub fn lit(value: Value, allow_object: bool) -> RbResult { if value.is_kind_of(class::true_class()) || value.is_kind_of(class::false_class()) { - Ok(dsl::lit(value.try_convert::()?).into()) + Ok(dsl::lit(bool::try_convert(value)?).into()) } else if let Some(v) = Integer::from_value(value) { - match v.try_convert::() { + match v.to_i64() { Ok(val) => { if val > 0 && val < i32::MAX as i64 || val < 0 && val > i32::MIN as i64 { Ok(dsl::lit(val as i32).into()) @@ -162,19 +168,19 @@ pub fn lit(value: Value, allow_object: bool) -> RbResult { } } _ => { - let val = value.try_convert::()?; + let val = v.to_u64()?; Ok(dsl::lit(val).into()) } } } else if let Some(v) = Float::from_value(value) { - Ok(dsl::lit(v.try_convert::()?).into()) + Ok(dsl::lit(v.to_f64()).into()) } else if let Some(v) = RString::from_value(value) { if v.enc_get() == encoding::Index::utf8() { - Ok(dsl::lit(v.try_convert::()?).into()) + Ok(dsl::lit(v.to_string()?).into()) } else { Ok(dsl::lit(unsafe { v.as_slice() }).into()) } - } else if let Ok(series) = value.try_convert::<&RbSeries>() { + } else if let Ok(series) = Obj::::try_convert(value) { Ok(dsl::lit(series.series.borrow().clone()).into()) } else if value.is_nil() { Ok(dsl::lit(Null {}).into()) @@ -236,7 +242,7 @@ pub fn concat_lst(s: RArray) -> RbResult { pub fn dtype_cols2(dtypes: RArray) -> RbResult { let dtypes = dtypes .each() - .map(|v| v?.try_convert::>()) + .map(|v| Wrap::::try_convert(v?)) .collect::>>>()?; let dtypes = vec_extract_wrapped(dtypes); Ok(crate::functions::lazy::dtype_cols(dtypes)) diff --git a/ext/polars/src/lazyframe.rs b/ext/polars/src/lazyframe.rs index 241b8b7f1b..e15528c320 100644 --- a/ext/polars/src/lazyframe.rs +++ b/ext/polars/src/lazyframe.rs @@ -1,4 +1,4 @@ -use magnus::{IntoValue, RArray, RHash, Value}; +use magnus::{IntoValue, RArray, RHash, TryConvert, Value}; use polars::io::RowCount; use polars::lazy::frame::LazyFrame; use polars::prelude::*; @@ -78,26 +78,26 @@ impl RbLazyFrame { pub fn new_from_csv(arguments: &[Value]) -> RbResult { // start arguments // this pattern is needed for more than 16 - let path: String = arguments[0].try_convert()?; - let sep: String = arguments[1].try_convert()?; - let has_header: bool = arguments[2].try_convert()?; - let ignore_errors: bool = arguments[3].try_convert()?; - let skip_rows: usize = arguments[4].try_convert()?; - let n_rows: Option = arguments[5].try_convert()?; - let cache: bool = arguments[6].try_convert()?; - let overwrite_dtype: Option)>> = arguments[7].try_convert()?; - let low_memory: bool = arguments[8].try_convert()?; - let comment_char: Option = arguments[9].try_convert()?; - let quote_char: Option = arguments[10].try_convert()?; - let null_values: Option> = arguments[11].try_convert()?; - let infer_schema_length: Option = arguments[12].try_convert()?; - let with_schema_modify: Option = arguments[13].try_convert()?; - let rechunk: bool = arguments[14].try_convert()?; - let skip_rows_after_header: usize = arguments[15].try_convert()?; - let encoding: Wrap = arguments[16].try_convert()?; - let row_count: Option<(String, IdxSize)> = arguments[17].try_convert()?; - let try_parse_dates: bool = arguments[18].try_convert()?; - let eol_char: String = arguments[19].try_convert()?; + let path = String::try_convert(arguments[0])?; + let sep = String::try_convert(arguments[1])?; + let has_header = bool::try_convert(arguments[2])?; + let ignore_errors = bool::try_convert(arguments[3])?; + let skip_rows = usize::try_convert(arguments[4])?; + let n_rows = Option::::try_convert(arguments[5])?; + let cache = bool::try_convert(arguments[6])?; + let overwrite_dtype = Option::)>>::try_convert(arguments[7])?; + let low_memory = bool::try_convert(arguments[8])?; + let comment_char = Option::::try_convert(arguments[9])?; + let quote_char = Option::::try_convert(arguments[10])?; + let null_values = Option::>::try_convert(arguments[11])?; + let infer_schema_length = Option::::try_convert(arguments[12])?; + let with_schema_modify = Option::::try_convert(arguments[13])?; + let rechunk = bool::try_convert(arguments[14])?; + let skip_rows_after_header = usize::try_convert(arguments[15])?; + let encoding = Wrap::::try_convert(arguments[16])?; + let row_count = Option::<(String, IdxSize)>::try_convert(arguments[17])?; + let try_parse_dates = bool::try_convert(arguments[18])?; + let eol_char = String::try_convert(arguments[19])?; // end arguments let null_values = null_values.map(|w| w.0); @@ -399,7 +399,7 @@ impl RbLazyFrame { pub fn with_context(&self, contexts: RArray) -> RbResult { let contexts = contexts .each() - .map(|v| v.unwrap().try_convert()) + .map(|v| TryConvert::try_convert(v.unwrap())) .collect::>>()?; let contexts = contexts .into_iter() diff --git a/ext/polars/src/lib.rs b/ext/polars/src/lib.rs index c41d859b9e..39d175748e 100644 --- a/ext/polars/src/lib.rs +++ b/ext/polars/src/lib.rs @@ -23,7 +23,7 @@ use expr::RbExpr; use functions::whenthen::{RbWhen, RbWhenThen}; use lazyframe::RbLazyFrame; use lazygroupby::RbLazyGroupBy; -use magnus::{define_module, function, method, prelude::*, Error}; +use magnus::{define_module, function, method, prelude::*, Error, Ruby}; use series::RbSeries; #[cfg(target_os = "linux")] @@ -43,7 +43,7 @@ static GLOBAL: MiMalloc = MiMalloc; type RbResult = Result; #[magnus::init] -fn init() -> RbResult<()> { +fn init(ruby: &Ruby) -> RbResult<()> { let module = define_module("Polars")?; module.define_singleton_method( "_dtype_cols", @@ -110,11 +110,11 @@ fn init() -> RbResult<()> { function!(crate::functions::meta::get_idx_type, 0), )?; - let class = module.define_class("RbBatchedCsv", Default::default())?; + let class = module.define_class("RbBatchedCsv", ruby.class_object())?; class.define_singleton_method("new", function!(RbBatchedCsv::new, -1))?; class.define_method("next_batches", method!(RbBatchedCsv::next_batches, 1))?; - let class = module.define_class("RbDataFrame", Default::default())?; + let class = module.define_class("RbDataFrame", ruby.class_object())?; class.define_singleton_method("new", function!(RbDataFrame::init, 1))?; class.define_singleton_method("read_csv", function!(RbDataFrame::read_csv, -1))?; class.define_singleton_method("read_parquet", function!(RbDataFrame::read_parquet, 9))?; @@ -217,7 +217,7 @@ fn init() -> RbResult<()> { class.define_method("to_struct", method!(RbDataFrame::to_struct, 1))?; class.define_method("unnest", method!(RbDataFrame::unnest, 1))?; - let class = module.define_class("RbExpr", Default::default())?; + let class = module.define_class("RbExpr", ruby.class_object())?; class.define_method("+", method!(RbExpr::add, 1))?; class.define_method("-", method!(RbExpr::sub, 1))?; class.define_method("*", method!(RbExpr::mul, 1))?; @@ -571,7 +571,7 @@ fn init() -> RbResult<()> { function!(crate::functions::lazy::concat_lst, 1), )?; - let class = module.define_class("RbLazyFrame", Default::default())?; + let class = module.define_class("RbLazyFrame", ruby.class_object())?; class.define_singleton_method("read_json", function!(RbLazyFrame::read_json, 1))?; class.define_singleton_method( "new_from_ndjson", @@ -636,12 +636,12 @@ fn init() -> RbResult<()> { class.define_method("unnest", method!(RbLazyFrame::unnest, 1))?; class.define_method("width", method!(RbLazyFrame::width, 0))?; - let class = module.define_class("RbLazyGroupBy", Default::default())?; + let class = module.define_class("RbLazyGroupBy", ruby.class_object())?; class.define_method("agg", method!(RbLazyGroupBy::agg, 1))?; class.define_method("head", method!(RbLazyGroupBy::head, 1))?; class.define_method("tail", method!(RbLazyGroupBy::tail, 1))?; - let class = module.define_class("RbSeries", Default::default())?; + let class = module.define_class("RbSeries", ruby.class_object())?; class.define_singleton_method("new_opt_bool", function!(RbSeries::new_opt_bool, 3))?; class.define_singleton_method("new_opt_u8", function!(RbSeries::new_opt_u8, 3))?; class.define_singleton_method("new_opt_u16", function!(RbSeries::new_opt_u16, 3))?; @@ -902,10 +902,10 @@ fn init() -> RbResult<()> { // extra class.define_method("extend_constant", method!(RbSeries::extend_constant, 2))?; - let class = module.define_class("RbWhen", Default::default())?; + let class = module.define_class("RbWhen", ruby.class_object())?; class.define_method("_then", method!(RbWhen::then, 1))?; - let class = module.define_class("RbWhenThen", Default::default())?; + let class = module.define_class("RbWhenThen", ruby.class_object())?; class.define_method("otherwise", method!(RbWhenThen::overwise, 1))?; Ok(()) diff --git a/ext/polars/src/object.rs b/ext/polars/src/object.rs index 9e111c675c..ea203e55f0 100644 --- a/ext/polars/src/object.rs +++ b/ext/polars/src/object.rs @@ -21,7 +21,7 @@ pub(crate) fn register_object_builder() { let object_converter = Arc::new(|av: AnyValue| { let object = ObjectValue { - inner: Wrap(av).into_value(), + inner: Wrap(av).into_value().into(), }; Box::new(object) as Box }); diff --git a/ext/polars/src/rb_modules.rs b/ext/polars/src/rb_modules.rs index 9bbc11fa2e..b31cc17ba3 100644 --- a/ext/polars/src/rb_modules.rs +++ b/ext/polars/src/rb_modules.rs @@ -1,25 +1,40 @@ -use magnus::{class, memoize, Module, RClass, RModule}; +use magnus::{value::Lazy, Module, RClass, RModule, Ruby}; + +static POLARS: Lazy = Lazy::new(|ruby| ruby.class_object().const_get("Polars").unwrap()); pub(crate) fn polars() -> RModule { - *memoize!(RModule: class::object().const_get("Polars").unwrap()) + Ruby::get().unwrap().get_inner(&POLARS) } +static SERIES: Lazy = + Lazy::new(|ruby| ruby.get_inner(&POLARS).const_get("Series").unwrap()); + pub(crate) fn series() -> RClass { - *memoize!(RClass: polars().const_get("Series").unwrap()) + Ruby::get().unwrap().get_inner(&SERIES) } +static UTILS: Lazy = Lazy::new(|ruby| ruby.get_inner(&POLARS).const_get("Utils").unwrap()); + pub(crate) fn utils() -> RModule { - *memoize!(RModule: polars().const_get("Utils").unwrap()) + Ruby::get().unwrap().get_inner(&UTILS) } +static BIGDECIMAL: Lazy = + Lazy::new(|ruby| ruby.class_object().const_get("BigDecimal").unwrap()); + pub(crate) fn bigdecimal() -> RClass { - *memoize!(RClass: class::object().const_get("BigDecimal").unwrap()) + Ruby::get().unwrap().get_inner(&BIGDECIMAL) } +static DATE: Lazy = Lazy::new(|ruby| ruby.class_object().const_get("Date").unwrap()); + pub(crate) fn date() -> RClass { - *memoize!(RClass: class::object().const_get("Date").unwrap()) + Ruby::get().unwrap().get_inner(&DATE) } +static DATETIME: Lazy = + Lazy::new(|ruby| ruby.class_object().const_get("DateTime").unwrap()); + pub(crate) fn datetime() -> RClass { - *memoize!(RClass: class::object().const_get("DateTime").unwrap()) + Ruby::get().unwrap().get_inner(&DATETIME) } diff --git a/ext/polars/src/series.rs b/ext/polars/src/series.rs index 0008f5cfe7..37264f2425 100644 --- a/ext/polars/src/series.rs +++ b/ext/polars/src/series.rs @@ -5,7 +5,7 @@ mod construction; mod export; mod set_at_idx; -use magnus::{exception, Error, IntoValue, RArray, Value, QNIL}; +use magnus::{exception, prelude::*, value::qnil, Error, IntoValue, RArray, Value}; use polars::prelude::*; use polars::series::IsSorted; use std::cell::RefCell; @@ -38,7 +38,7 @@ impl RbSeries { pub fn to_series_collection(rs: RArray) -> RbResult> { let mut series = Vec::new(); for item in rs.each() { - series.push(item?.try_convert::<&RbSeries>()?.series.borrow().clone()); + series.push(<&RbSeries>::try_convert(item?)?.series.borrow().clone()); } Ok(series) } @@ -325,7 +325,7 @@ impl RbSeries { let obj: Option<&ObjectValue> = series.get_object(i).map(|any| any.into()); match obj { Some(val) => v.push(val.to_object()).unwrap(), - None => v.push(QNIL).unwrap(), + None => v.push(qnil()).unwrap(), }; } v.into_value() @@ -336,7 +336,7 @@ impl RbSeries { for opt_s in ca.amortized_iter() { match opt_s { None => { - v.push(QNIL).unwrap(); + v.push(qnil()).unwrap(); } Some(s) => { let rblst = to_a_recursive(s.as_ref()); @@ -352,7 +352,7 @@ impl RbSeries { for opt_s in ca.amortized_iter() { match opt_s { None => { - v.push(QNIL).unwrap(); + v.push(qnil()).unwrap(); } Some(s) => { let rblst = to_a_recursive(s.as_ref()); diff --git a/ext/polars/src/series/construction.rs b/ext/polars/src/series/construction.rs index 36a3a509bd..6a545886a1 100644 --- a/ext/polars/src/series/construction.rs +++ b/ext/polars/src/series/construction.rs @@ -1,4 +1,4 @@ -use magnus::RArray; +use magnus::{prelude::*, RArray}; use polars_core::prelude::*; use crate::conversion::{slice_extract_wrapped, vec_extract_wrapped, Wrap}; @@ -16,7 +16,7 @@ impl RbSeries { if item.is_nil() { builder.append_null() } else { - match item.try_convert::() { + match bool::try_convert(*item) { Ok(val) => builder.append_value(val), Err(e) => { if strict { @@ -49,7 +49,7 @@ where if item.is_nil() { builder.append_null() } else { - match item.try_convert::() { + match T::Native::try_convert(*item) { Ok(val) => builder.append_value(val), Err(e) => { if strict { @@ -92,7 +92,7 @@ init_method_opt!(new_opt_f64, Float64Type, f64); fn vec_wrap_any_value<'s>(arr: RArray) -> RbResult>>> { let mut val = Vec::with_capacity(arr.len()); for v in arr.each() { - val.push(v?.try_convert()?); + val.push(Wrap::>::try_convert(v?)?); } Ok(val) } diff --git a/ext/polars/src/series/export.rs b/ext/polars/src/series/export.rs index bce99ea89a..bf54c9d9ec 100644 --- a/ext/polars/src/series/export.rs +++ b/ext/polars/src/series/export.rs @@ -1,4 +1,4 @@ -use magnus::{class, Module, RArray, RClass, RModule, Value}; +use magnus::{class, prelude::*, Module, RArray, RClass, RModule, Value}; use polars_core::prelude::*; use crate::{raise_err, RbPolarsErr, RbResult, RbSeries};