polars-df 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -0
  3. data/Cargo.lock +468 -538
  4. data/Cargo.toml +1 -0
  5. data/README.md +8 -7
  6. data/ext/polars/Cargo.toml +17 -10
  7. data/ext/polars/src/batched_csv.rs +26 -26
  8. data/ext/polars/src/conversion.rs +121 -93
  9. data/ext/polars/src/dataframe.rs +116 -71
  10. data/ext/polars/src/error.rs +0 -5
  11. data/ext/polars/src/expr/binary.rs +18 -6
  12. data/ext/polars/src/expr/datetime.rs +10 -12
  13. data/ext/polars/src/expr/general.rs +68 -284
  14. data/ext/polars/src/expr/list.rs +17 -9
  15. data/ext/polars/src/{expr.rs → expr/mod.rs} +4 -2
  16. data/ext/polars/src/expr/name.rs +44 -0
  17. data/ext/polars/src/expr/rolling.rs +196 -0
  18. data/ext/polars/src/expr/string.rs +85 -58
  19. data/ext/polars/src/file.rs +3 -3
  20. data/ext/polars/src/functions/aggregation.rs +35 -0
  21. data/ext/polars/src/functions/eager.rs +7 -31
  22. data/ext/polars/src/functions/io.rs +10 -10
  23. data/ext/polars/src/functions/lazy.rs +66 -41
  24. data/ext/polars/src/functions/meta.rs +30 -0
  25. data/ext/polars/src/functions/misc.rs +8 -0
  26. data/ext/polars/src/functions/mod.rs +5 -0
  27. data/ext/polars/src/functions/random.rs +6 -0
  28. data/ext/polars/src/functions/range.rs +46 -0
  29. data/ext/polars/src/functions/string_cache.rs +11 -0
  30. data/ext/polars/src/functions/whenthen.rs +7 -7
  31. data/ext/polars/src/lazyframe.rs +47 -42
  32. data/ext/polars/src/lib.rs +156 -72
  33. data/ext/polars/src/{apply → map}/dataframe.rs +28 -33
  34. data/ext/polars/src/{apply → map}/mod.rs +3 -3
  35. data/ext/polars/src/{apply → map}/series.rs +12 -16
  36. data/ext/polars/src/object.rs +1 -1
  37. data/ext/polars/src/rb_modules.rs +22 -7
  38. data/ext/polars/src/series/construction.rs +4 -4
  39. data/ext/polars/src/series/export.rs +2 -2
  40. data/ext/polars/src/series/set_at_idx.rs +33 -17
  41. data/ext/polars/src/series.rs +7 -27
  42. data/ext/polars/src/sql.rs +46 -0
  43. data/lib/polars/config.rb +530 -0
  44. data/lib/polars/data_frame.rb +115 -82
  45. data/lib/polars/date_time_expr.rb +13 -18
  46. data/lib/polars/date_time_name_space.rb +5 -25
  47. data/lib/polars/dynamic_group_by.rb +2 -2
  48. data/lib/polars/expr.rb +177 -94
  49. data/lib/polars/functions.rb +29 -37
  50. data/lib/polars/group_by.rb +38 -55
  51. data/lib/polars/io.rb +37 -2
  52. data/lib/polars/lazy_frame.rb +93 -66
  53. data/lib/polars/lazy_functions.rb +36 -48
  54. data/lib/polars/lazy_group_by.rb +7 -8
  55. data/lib/polars/list_expr.rb +12 -8
  56. data/lib/polars/list_name_space.rb +2 -2
  57. data/lib/polars/name_expr.rb +198 -0
  58. data/lib/polars/rolling_group_by.rb +2 -2
  59. data/lib/polars/series.rb +26 -13
  60. data/lib/polars/sql_context.rb +194 -0
  61. data/lib/polars/string_expr.rb +114 -60
  62. data/lib/polars/string_name_space.rb +19 -4
  63. data/lib/polars/utils.rb +12 -0
  64. data/lib/polars/version.rb +1 -1
  65. data/lib/polars.rb +3 -0
  66. metadata +18 -7
  67. /data/ext/polars/src/{apply → map}/lazy.rs +0 -0
@@ -1,10 +1,10 @@
1
- use std::fmt::{Display, Formatter};
1
+ use std::fmt::{Debug, Display, Formatter};
2
2
  use std::hash::{Hash, Hasher};
3
3
 
4
4
  use magnus::encoding::{EncodingCapable, Index};
5
5
  use magnus::{
6
- class, exception, r_hash::ForEach, ruby_handle::RubyHandle, Float, Integer, IntoValue, Module,
7
- RArray, RHash, RString, Symbol, TryConvert, Value, QNIL,
6
+ class, exception, prelude::*, r_hash::ForEach, value::Opaque, Float, Integer, IntoValue,
7
+ Module, RArray, RHash, RString, Ruby, Symbol, TryConvert, Value,
8
8
  };
9
9
  use polars::chunked_array::object::PolarsObjectSafe;
10
10
  use polars::chunked_array::ops::{FillNullLimit, FillNullStrategy};
@@ -14,6 +14,7 @@ use polars::frame::NullStrategy;
14
14
  use polars::io::avro::AvroCompression;
15
15
  use polars::prelude::*;
16
16
  use polars::series::ops::NullBehavior;
17
+ use polars_core::utils::arrow::util::total_ord::TotalEq;
17
18
  use smartstring::alias::String as SmartString;
18
19
 
19
20
  use crate::object::OBJECT_NAME;
@@ -57,7 +58,7 @@ impl<T> From<T> for Wrap<T> {
57
58
  }
58
59
 
59
60
  pub(crate) fn get_rbseq(obj: Value) -> RbResult<(RArray, usize)> {
60
- let seq: RArray = obj.try_convert()?;
61
+ let seq = RArray::try_convert(obj)?;
61
62
  let len = seq.len();
62
63
  Ok((seq, len))
63
64
  }
@@ -84,7 +85,7 @@ impl TryConvert for Wrap<Utf8Chunked> {
84
85
 
85
86
  for res in seq.each() {
86
87
  let item = res?;
87
- match item.try_convert::<String>() {
88
+ match String::try_convert(item) {
88
89
  Ok(val) => builder.append_value(&val),
89
90
  Err(_) => builder.append_null(),
90
91
  }
@@ -100,7 +101,7 @@ impl TryConvert for Wrap<BinaryChunked> {
100
101
 
101
102
  for res in seq.each() {
102
103
  let item = res?;
103
- match item.try_convert::<RString>() {
104
+ match RString::try_convert(item) {
104
105
  Ok(val) => builder.append_value(unsafe { val.as_slice() }),
105
106
  Err(_) => builder.append_null(),
106
107
  }
@@ -111,11 +112,11 @@ impl TryConvert for Wrap<BinaryChunked> {
111
112
 
112
113
  impl TryConvert for Wrap<NullValues> {
113
114
  fn try_convert(ob: Value) -> RbResult<Self> {
114
- if let Ok(s) = ob.try_convert::<String>() {
115
+ if let Ok(s) = String::try_convert(ob) {
115
116
  Ok(Wrap(NullValues::AllColumnsSingle(s)))
116
- } else if let Ok(s) = ob.try_convert::<Vec<String>>() {
117
+ } else if let Ok(s) = Vec::<String>::try_convert(ob) {
117
118
  Ok(Wrap(NullValues::AllColumns(s)))
118
- } else if let Ok(s) = ob.try_convert::<Vec<(String, String)>>() {
119
+ } else if let Ok(s) = Vec::<(String, String)>::try_convert(ob) {
119
120
  Ok(Wrap(NullValues::Named(s)))
120
121
  } else {
121
122
  Err(RbPolarsErr::other(
@@ -134,22 +135,22 @@ fn struct_dict<'a>(vals: impl Iterator<Item = AnyValue<'a>>, flds: &[Field]) ->
134
135
  }
135
136
 
136
137
  impl IntoValue for Wrap<AnyValue<'_>> {
137
- fn into_value_with(self, _: &RubyHandle) -> Value {
138
+ fn into_value_with(self, ruby: &Ruby) -> Value {
138
139
  match self.0 {
139
- AnyValue::UInt8(v) => Value::from(v),
140
- AnyValue::UInt16(v) => Value::from(v),
141
- AnyValue::UInt32(v) => Value::from(v),
142
- AnyValue::UInt64(v) => Value::from(v),
143
- AnyValue::Int8(v) => Value::from(v),
144
- AnyValue::Int16(v) => Value::from(v),
145
- AnyValue::Int32(v) => Value::from(v),
146
- AnyValue::Int64(v) => Value::from(v),
147
- AnyValue::Float32(v) => Value::from(v),
148
- AnyValue::Float64(v) => Value::from(v),
149
- AnyValue::Null => *QNIL,
150
- AnyValue::Boolean(v) => Value::from(v),
151
- AnyValue::Utf8(v) => Value::from(v),
152
- AnyValue::Utf8Owned(v) => Value::from(v.as_str()),
140
+ AnyValue::UInt8(v) => ruby.into_value(v),
141
+ AnyValue::UInt16(v) => ruby.into_value(v),
142
+ AnyValue::UInt32(v) => ruby.into_value(v),
143
+ AnyValue::UInt64(v) => ruby.into_value(v),
144
+ AnyValue::Int8(v) => ruby.into_value(v),
145
+ AnyValue::Int16(v) => ruby.into_value(v),
146
+ AnyValue::Int32(v) => ruby.into_value(v),
147
+ AnyValue::Int64(v) => ruby.into_value(v),
148
+ AnyValue::Float32(v) => ruby.into_value(v),
149
+ AnyValue::Float64(v) => ruby.into_value(v),
150
+ AnyValue::Null => ruby.qnil().as_value(),
151
+ AnyValue::Boolean(v) => ruby.into_value(v),
152
+ AnyValue::Utf8(v) => ruby.into_value(v),
153
+ AnyValue::Utf8Owned(v) => ruby.into_value(v.as_str()),
153
154
  AnyValue::Categorical(idx, rev, arr) => {
154
155
  let s = if arr.is_null() {
155
156
  rev.get(idx)
@@ -177,11 +178,11 @@ impl IntoValue for Wrap<AnyValue<'_>> {
177
178
  AnyValue::StructOwned(payload) => struct_dict(payload.0.into_iter(), &payload.1),
178
179
  AnyValue::Object(v) => {
179
180
  let object = v.as_any().downcast_ref::<ObjectValue>().unwrap();
180
- object.inner
181
+ object.to_object()
181
182
  }
182
183
  AnyValue::ObjectOwned(v) => {
183
184
  let object = v.0.as_any().downcast_ref::<ObjectValue>().unwrap();
184
- object.inner
185
+ object.to_object()
185
186
  }
186
187
  AnyValue::Binary(v) => RString::from_slice(v).into_value(),
187
188
  AnyValue::BinaryOwned(v) => RString::from_slice(&v).into_value(),
@@ -193,7 +194,7 @@ impl IntoValue for Wrap<AnyValue<'_>> {
193
194
  }
194
195
 
195
196
  impl IntoValue for Wrap<DataType> {
196
- fn into_value_with(self, _: &RubyHandle) -> Value {
197
+ fn into_value_with(self, _: &Ruby) -> Value {
197
198
  let pl = crate::rb_modules::polars();
198
199
 
199
200
  match self.0 {
@@ -266,7 +267,7 @@ impl IntoValue for Wrap<DataType> {
266
267
  }
267
268
 
268
269
  impl IntoValue for Wrap<TimeUnit> {
269
- fn into_value_with(self, _: &RubyHandle) -> Value {
270
+ fn into_value_with(self, _: &Ruby) -> Value {
270
271
  let tu = match self.0 {
271
272
  TimeUnit::Nanoseconds => "ns",
272
273
  TimeUnit::Microseconds => "us",
@@ -277,14 +278,14 @@ impl IntoValue for Wrap<TimeUnit> {
277
278
  }
278
279
 
279
280
  impl IntoValue for Wrap<&Utf8Chunked> {
280
- fn into_value_with(self, _: &RubyHandle) -> Value {
281
+ fn into_value_with(self, _: &Ruby) -> Value {
281
282
  let iter = self.0.into_iter();
282
283
  RArray::from_iter(iter).into_value()
283
284
  }
284
285
  }
285
286
 
286
287
  impl IntoValue for Wrap<&BinaryChunked> {
287
- fn into_value_with(self, _: &RubyHandle) -> Value {
288
+ fn into_value_with(self, _: &Ruby) -> Value {
288
289
  let iter = self
289
290
  .0
290
291
  .into_iter()
@@ -294,7 +295,7 @@ impl IntoValue for Wrap<&BinaryChunked> {
294
295
  }
295
296
 
296
297
  impl IntoValue for Wrap<&StructChunked> {
297
- fn into_value_with(self, _: &RubyHandle) -> Value {
298
+ fn into_value_with(self, _: &Ruby) -> Value {
298
299
  let s = self.0.clone().into_series();
299
300
  // todo! iterate its chunks and flatten.
300
301
  // make series::iter() accept a chunk index.
@@ -312,7 +313,7 @@ impl IntoValue for Wrap<&StructChunked> {
312
313
  }
313
314
 
314
315
  impl IntoValue for Wrap<&DurationChunked> {
315
- fn into_value_with(self, _: &RubyHandle) -> Value {
316
+ fn into_value_with(self, _: &Ruby) -> Value {
316
317
  let utils = utils();
317
318
  let time_unit = Wrap(self.0.time_unit()).into_value();
318
319
  let iter = self.0.into_iter().map(|opt_v| {
@@ -327,7 +328,7 @@ impl IntoValue for Wrap<&DurationChunked> {
327
328
  }
328
329
 
329
330
  impl IntoValue for Wrap<&DatetimeChunked> {
330
- fn into_value_with(self, _: &RubyHandle) -> Value {
331
+ fn into_value_with(self, _: &Ruby) -> Value {
331
332
  let utils = utils();
332
333
  let time_unit = Wrap(self.0.time_unit()).into_value();
333
334
  let time_zone = self.0.time_zone().clone().into_value();
@@ -343,7 +344,7 @@ impl IntoValue for Wrap<&DatetimeChunked> {
343
344
  }
344
345
 
345
346
  impl IntoValue for Wrap<&TimeChunked> {
346
- fn into_value_with(self, _: &RubyHandle) -> Value {
347
+ fn into_value_with(self, _: &Ruby) -> Value {
347
348
  let utils = utils();
348
349
  let iter = self.0.into_iter().map(|opt_v| {
349
350
  opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_time", (v,)).unwrap())
@@ -353,7 +354,7 @@ impl IntoValue for Wrap<&TimeChunked> {
353
354
  }
354
355
 
355
356
  impl IntoValue for Wrap<&DateChunked> {
356
- fn into_value_with(self, _: &RubyHandle) -> Value {
357
+ fn into_value_with(self, _: &Ruby) -> Value {
357
358
  let utils = utils();
358
359
  let iter = self.0.into_iter().map(|opt_v| {
359
360
  opt_v.map(|v| utils.funcall::<_, _, Value>("_to_ruby_date", (v,)).unwrap())
@@ -363,7 +364,7 @@ impl IntoValue for Wrap<&DateChunked> {
363
364
  }
364
365
 
365
366
  impl IntoValue for Wrap<&DecimalChunked> {
366
- fn into_value_with(self, _: &RubyHandle) -> Value {
367
+ fn into_value_with(self, _: &Ruby) -> Value {
367
368
  let utils = utils();
368
369
  let rb_scale = (-(self.0.scale() as i32)).into_value();
369
370
  let iter = self.0.into_iter().map(|opt_v| {
@@ -427,36 +428,35 @@ impl TryConvert for Wrap<DataType> {
427
428
  }
428
429
  }
429
430
  // TODO improve
430
- } else if ob.try_convert::<String>().is_err() {
431
+ } else if String::try_convert(ob).is_err() {
431
432
  let name = unsafe { ob.class().name() }.into_owned();
432
433
  match name.as_str() {
433
434
  "Polars::Duration" => {
434
435
  let time_unit: Value = ob.funcall("time_unit", ()).unwrap();
435
- let time_unit = time_unit.try_convert::<Wrap<TimeUnit>>()?.0;
436
+ let time_unit = Wrap::<TimeUnit>::try_convert(time_unit)?.0;
436
437
  DataType::Duration(time_unit)
437
438
  }
438
439
  "Polars::Datetime" => {
439
440
  let time_unit: Value = ob.funcall("time_unit", ()).unwrap();
440
- let time_unit = time_unit.try_convert::<Wrap<TimeUnit>>()?.0;
441
- let time_zone: Value = ob.funcall("time_zone", ()).unwrap();
442
- let time_zone = time_zone.try_convert()?;
441
+ let time_unit = Wrap::<TimeUnit>::try_convert(time_unit)?.0;
442
+ let time_zone = ob.funcall("time_zone", ())?;
443
443
  DataType::Datetime(time_unit, time_zone)
444
444
  }
445
445
  "Polars::Decimal" => {
446
- let precision = ob.funcall::<_, _, Value>("precision", ())?.try_convert()?;
447
- let scale = ob.funcall::<_, _, Value>("scale", ())?.try_convert()?;
446
+ let precision = ob.funcall("precision", ())?;
447
+ let scale = ob.funcall("scale", ())?;
448
448
  DataType::Decimal(precision, Some(scale))
449
449
  }
450
450
  "Polars::List" => {
451
451
  let inner: Value = ob.funcall("inner", ()).unwrap();
452
- let inner = inner.try_convert::<Wrap<DataType>>()?;
452
+ let inner = Wrap::<DataType>::try_convert(inner)?;
453
453
  DataType::List(Box::new(inner.0))
454
454
  }
455
455
  "Polars::Struct" => {
456
456
  let arr: RArray = ob.funcall("fields", ())?;
457
457
  let mut fields = Vec::with_capacity(arr.len());
458
458
  for v in arr.each() {
459
- fields.push(v?.try_convert::<Wrap<Field>>()?.0);
459
+ fields.push(Wrap::<Field>::try_convert(v?)?.0);
460
460
  }
461
461
  DataType::Struct(fields)
462
462
  }
@@ -468,7 +468,7 @@ impl TryConvert for Wrap<DataType> {
468
468
  }
469
469
  }
470
470
  } else {
471
- match ob.try_convert::<String>()?.as_str() {
471
+ match String::try_convert(ob)?.as_str() {
472
472
  "u8" => DataType::UInt8,
473
473
  "u16" => DataType::UInt16,
474
474
  "u32" => DataType::UInt32,
@@ -487,7 +487,7 @@ impl TryConvert for Wrap<DataType> {
487
487
  "time" => DataType::Time,
488
488
  "dur" => DataType::Duration(TimeUnit::Microseconds),
489
489
  "f64" => DataType::Float64,
490
- // "obj" => DataType::Object(OBJECT_NAME),
490
+ "obj" => DataType::Object(OBJECT_NAME),
491
491
  "list" => DataType::List(Box::new(DataType::Boolean)),
492
492
  "null" => DataType::Null,
493
493
  "unk" => DataType::Unknown,
@@ -506,7 +506,7 @@ impl TryConvert for Wrap<DataType> {
506
506
  impl<'s> TryConvert for Wrap<AnyValue<'s>> {
507
507
  fn try_convert(ob: Value) -> RbResult<Self> {
508
508
  if ob.is_kind_of(class::true_class()) || ob.is_kind_of(class::false_class()) {
509
- Ok(AnyValue::Boolean(ob.try_convert::<bool>()?).into())
509
+ Ok(AnyValue::Boolean(bool::try_convert(ob)?).into())
510
510
  } else if let Some(v) = Integer::from_value(ob) {
511
511
  Ok(AnyValue::Int64(v.to_i64()?).into())
512
512
  } else if let Some(v) = Float::from_value(ob) {
@@ -532,8 +532,8 @@ impl<'s> TryConvert for Wrap<AnyValue<'s>> {
532
532
  let mut keys = Vec::with_capacity(len);
533
533
  let mut vals = Vec::with_capacity(len);
534
534
  dict.foreach(|k: Value, v: Value| {
535
- let key = k.try_convert::<String>()?;
536
- let val = v.try_convert::<Wrap<AnyValue>>()?.0;
535
+ let key = String::try_convert(k)?;
536
+ let val = Wrap::<AnyValue>::try_convert(v)?.0;
537
537
  let dtype = DataType::from(&val);
538
538
  keys.push(Field::new(&key, dtype));
539
539
  vals.push(val);
@@ -550,7 +550,7 @@ impl<'s> TryConvert for Wrap<AnyValue<'s>> {
550
550
  let mut iter = list.each();
551
551
 
552
552
  for item in (&mut iter).take(25) {
553
- avs.push(item?.try_convert::<Wrap<AnyValue>>()?.0)
553
+ avs.push(Wrap::<AnyValue>::try_convert(item?)?.0)
554
554
  }
555
555
 
556
556
  let (dtype, _n_types) = any_values_to_dtype(&avs).map_err(RbPolarsErr::from)?;
@@ -558,7 +558,7 @@ impl<'s> TryConvert for Wrap<AnyValue<'s>> {
558
558
  // push the rest
559
559
  avs.reserve(list.len());
560
560
  for item in iter {
561
- avs.push(item?.try_convert::<Wrap<AnyValue>>()?.0)
561
+ avs.push(Wrap::<AnyValue>::try_convert(item?)?.0)
562
562
  }
563
563
 
564
564
  let s = Series::from_any_values_and_dtype("", &avs, &dtype, true)
@@ -581,11 +581,7 @@ impl<'s> TryConvert for Wrap<AnyValue<'s>> {
581
581
  .funcall::<_, _, i64>("to_i", ())?;
582
582
  Ok(Wrap(AnyValue::Date((v / 86400) as i32)))
583
583
  } else if ob.is_kind_of(crate::rb_modules::bigdecimal()) {
584
- let (sign, digits, _, exp): (i8, String, i32, i32) = ob
585
- .funcall::<_, _, Value>("split", ())
586
- .unwrap()
587
- .try_convert()
588
- .unwrap();
584
+ let (sign, digits, _, exp): (i8, String, i32, i32) = ob.funcall("split", ()).unwrap();
589
585
  let (mut v, scale) = abs_decimal_from_digits(digits, exp).ok_or_else(|| {
590
586
  RbPolarsErr::other("BigDecimal is too large to fit in Decimal128".into())
591
587
  })?;
@@ -606,8 +602,8 @@ impl<'s> TryConvert for Wrap<AnyValue<'s>> {
606
602
  impl<'s> TryConvert for Wrap<Row<'s>> {
607
603
  fn try_convert(ob: Value) -> RbResult<Self> {
608
604
  let mut vals: Vec<Wrap<AnyValue<'s>>> = Vec::new();
609
- for item in ob.try_convert::<RArray>()?.each() {
610
- vals.push(item?.try_convert::<Wrap<AnyValue<'s>>>()?);
605
+ for item in RArray::try_convert(ob)?.each() {
606
+ vals.push(Wrap::<AnyValue<'s>>::try_convert(item?)?);
611
607
  }
612
608
  let vals: Vec<AnyValue> = unsafe { std::mem::transmute(vals) };
613
609
  Ok(Wrap(Row(vals)))
@@ -616,7 +612,7 @@ impl<'s> TryConvert for Wrap<Row<'s>> {
616
612
 
617
613
  impl TryConvert for Wrap<Schema> {
618
614
  fn try_convert(ob: Value) -> RbResult<Self> {
619
- let dict = ob.try_convert::<RHash>()?;
615
+ let dict = RHash::try_convert(ob)?;
620
616
 
621
617
  let mut schema = Vec::new();
622
618
  dict.foreach(|key: String, val: Wrap<DataType>| {
@@ -629,15 +625,23 @@ impl TryConvert for Wrap<Schema> {
629
625
  }
630
626
  }
631
627
 
632
- #[derive(Clone, Debug)]
628
+ #[derive(Clone)]
633
629
  pub struct ObjectValue {
634
- pub inner: Value,
630
+ pub inner: Opaque<Value>,
631
+ }
632
+
633
+ impl Debug for ObjectValue {
634
+ fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
635
+ f.debug_struct("ObjectValue")
636
+ .field("inner", &self.to_object())
637
+ .finish()
638
+ }
635
639
  }
636
640
 
637
641
  impl Hash for ObjectValue {
638
642
  fn hash<H: Hasher>(&self, state: &mut H) {
639
643
  let h = self
640
- .inner
644
+ .to_object()
641
645
  .funcall::<_, _, isize>("hash", ())
642
646
  .expect("should be hashable");
643
647
  state.write_isize(h)
@@ -648,13 +652,19 @@ impl Eq for ObjectValue {}
648
652
 
649
653
  impl PartialEq for ObjectValue {
650
654
  fn eq(&self, other: &Self) -> bool {
651
- self.inner.eql(&other.inner).unwrap_or(false)
655
+ self.to_object().eql(other.to_object()).unwrap_or(false)
656
+ }
657
+ }
658
+
659
+ impl TotalEq for ObjectValue {
660
+ fn tot_eq(&self, other: &Self) -> bool {
661
+ self == other
652
662
  }
653
663
  }
654
664
 
655
665
  impl Display for ObjectValue {
656
666
  fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
657
- write!(f, "{}", self.inner)
667
+ write!(f, "{}", self.to_object())
658
668
  }
659
669
  }
660
670
 
@@ -666,13 +676,13 @@ impl PolarsObject for ObjectValue {
666
676
 
667
677
  impl From<Value> for ObjectValue {
668
678
  fn from(v: Value) -> Self {
669
- Self { inner: v }
679
+ Self { inner: v.into() }
670
680
  }
671
681
  }
672
682
 
673
683
  impl TryConvert for ObjectValue {
674
684
  fn try_convert(ob: Value) -> RbResult<Self> {
675
- Ok(ObjectValue { inner: ob })
685
+ Ok(ObjectValue { inner: ob.into() })
676
686
  }
677
687
  }
678
688
 
@@ -685,19 +695,21 @@ impl From<&dyn PolarsObjectSafe> for &ObjectValue {
685
695
  // TODO remove
686
696
  impl ObjectValue {
687
697
  pub fn to_object(&self) -> Value {
688
- self.inner
698
+ Ruby::get().unwrap().get_inner(self.inner)
689
699
  }
690
700
  }
691
701
 
692
702
  impl IntoValue for ObjectValue {
693
- fn into_value_with(self, _: &RubyHandle) -> Value {
694
- self.inner
703
+ fn into_value_with(self, _: &Ruby) -> Value {
704
+ self.to_object()
695
705
  }
696
706
  }
697
707
 
698
708
  impl Default for ObjectValue {
699
709
  fn default() -> Self {
700
- ObjectValue { inner: *QNIL }
710
+ ObjectValue {
711
+ inner: Ruby::get().unwrap().qnil().as_value().into(),
712
+ }
701
713
  }
702
714
  }
703
715
 
@@ -710,13 +722,13 @@ pub(crate) fn dicts_to_rows(
710
722
  let mut key_names = PlIndexSet::new();
711
723
  for d in dicts.each().take(infer_schema_len) {
712
724
  let d = d?;
713
- let d = d.try_convert::<RHash>()?;
725
+ let d = RHash::try_convert(d)?;
714
726
 
715
727
  d.foreach(|name: Value, _value: Value| {
716
728
  if let Some(v) = Symbol::from_value(name) {
717
729
  key_names.insert(v.name()?.into());
718
730
  } else {
719
- key_names.insert(name.try_convert::<String>()?);
731
+ key_names.insert(String::try_convert(name)?);
720
732
  };
721
733
  Ok(ForEach::Continue)
722
734
  })?;
@@ -726,7 +738,7 @@ pub(crate) fn dicts_to_rows(
726
738
 
727
739
  for d in dicts.each() {
728
740
  let d = d?;
729
- let d = d.try_convert::<RHash>()?;
741
+ let d = RHash::try_convert(d)?;
730
742
 
731
743
  let mut row = Vec::with_capacity(key_names.len());
732
744
 
@@ -734,7 +746,7 @@ pub(crate) fn dicts_to_rows(
734
746
  // TODO improve performance
735
747
  let val = match d.get(k.clone()).or_else(|| d.get(Symbol::new(k))) {
736
748
  None => AnyValue::Null,
737
- Some(val) => val.try_convert::<Wrap<AnyValue>>()?.0,
749
+ Some(val) => Wrap::<AnyValue>::try_convert(val)?.0,
738
750
  };
739
751
  row.push(val)
740
752
  }
@@ -745,7 +757,7 @@ pub(crate) fn dicts_to_rows(
745
757
 
746
758
  impl TryConvert for Wrap<AsofStrategy> {
747
759
  fn try_convert(ob: Value) -> RbResult<Self> {
748
- let parsed = match ob.try_convert::<String>()?.as_str() {
760
+ let parsed = match String::try_convert(ob)?.as_str() {
749
761
  "backward" => AsofStrategy::Backward,
750
762
  "forward" => AsofStrategy::Forward,
751
763
  v => {
@@ -761,7 +773,7 @@ impl TryConvert for Wrap<AsofStrategy> {
761
773
 
762
774
  impl TryConvert for Wrap<InterpolationMethod> {
763
775
  fn try_convert(ob: Value) -> RbResult<Self> {
764
- let parsed = match ob.try_convert::<String>()?.as_str() {
776
+ let parsed = match String::try_convert(ob)?.as_str() {
765
777
  "linear" => InterpolationMethod::Linear,
766
778
  "nearest" => InterpolationMethod::Nearest,
767
779
  v => {
@@ -776,7 +788,7 @@ impl TryConvert for Wrap<InterpolationMethod> {
776
788
 
777
789
  impl TryConvert for Wrap<Option<AvroCompression>> {
778
790
  fn try_convert(ob: Value) -> RbResult<Self> {
779
- let parsed = match ob.try_convert::<String>()?.as_str() {
791
+ let parsed = match String::try_convert(ob)?.as_str() {
780
792
  "uncompressed" => None,
781
793
  "snappy" => Some(AvroCompression::Snappy),
782
794
  "deflate" => Some(AvroCompression::Deflate),
@@ -793,7 +805,7 @@ impl TryConvert for Wrap<Option<AvroCompression>> {
793
805
 
794
806
  impl TryConvert for Wrap<CategoricalOrdering> {
795
807
  fn try_convert(ob: Value) -> RbResult<Self> {
796
- let parsed = match ob.try_convert::<String>()?.as_str() {
808
+ let parsed = match String::try_convert(ob)?.as_str() {
797
809
  "physical" => CategoricalOrdering::Physical,
798
810
  "lexical" => CategoricalOrdering::Lexical,
799
811
  v => {
@@ -809,7 +821,7 @@ impl TryConvert for Wrap<CategoricalOrdering> {
809
821
 
810
822
  impl TryConvert for Wrap<StartBy> {
811
823
  fn try_convert(ob: Value) -> RbResult<Self> {
812
- let parsed = match ob.try_convert::<String>()?.as_str() {
824
+ let parsed = match String::try_convert(ob)?.as_str() {
813
825
  "window" => StartBy::WindowBound,
814
826
  "datapoint" => StartBy::DataPoint,
815
827
  "monday" => StartBy::Monday,
@@ -825,7 +837,7 @@ impl TryConvert for Wrap<StartBy> {
825
837
 
826
838
  impl TryConvert for Wrap<ClosedWindow> {
827
839
  fn try_convert(ob: Value) -> RbResult<Self> {
828
- let parsed = match ob.try_convert::<String>()?.as_str() {
840
+ let parsed = match String::try_convert(ob)?.as_str() {
829
841
  "left" => ClosedWindow::Left,
830
842
  "right" => ClosedWindow::Right,
831
843
  "both" => ClosedWindow::Both,
@@ -843,7 +855,7 @@ impl TryConvert for Wrap<ClosedWindow> {
843
855
 
844
856
  impl TryConvert for Wrap<CsvEncoding> {
845
857
  fn try_convert(ob: Value) -> RbResult<Self> {
846
- let parsed = match ob.try_convert::<String>()?.as_str() {
858
+ let parsed = match String::try_convert(ob)?.as_str() {
847
859
  "utf8" => CsvEncoding::Utf8,
848
860
  "utf8-lossy" => CsvEncoding::LossyUtf8,
849
861
  v => {
@@ -859,7 +871,7 @@ impl TryConvert for Wrap<CsvEncoding> {
859
871
 
860
872
  impl TryConvert for Wrap<Option<IpcCompression>> {
861
873
  fn try_convert(ob: Value) -> RbResult<Self> {
862
- let parsed = match ob.try_convert::<String>()?.as_str() {
874
+ let parsed = match String::try_convert(ob)?.as_str() {
863
875
  "uncompressed" => None,
864
876
  "lz4" => Some(IpcCompression::LZ4),
865
877
  "zstd" => Some(IpcCompression::ZSTD),
@@ -876,7 +888,7 @@ impl TryConvert for Wrap<Option<IpcCompression>> {
876
888
 
877
889
  impl TryConvert for Wrap<JoinType> {
878
890
  fn try_convert(ob: Value) -> RbResult<Self> {
879
- let parsed = match ob.try_convert::<String>()?.as_str() {
891
+ let parsed = match String::try_convert(ob)?.as_str() {
880
892
  "inner" => JoinType::Inner,
881
893
  "left" => JoinType::Left,
882
894
  "outer" => JoinType::Outer,
@@ -895,9 +907,25 @@ impl TryConvert for Wrap<JoinType> {
895
907
  }
896
908
  }
897
909
 
910
+ impl TryConvert for Wrap<Label> {
911
+ fn try_convert(ob: Value) -> RbResult<Self> {
912
+ let parsed = match String::try_convert(ob)?.as_str() {
913
+ "left" => Label::Left,
914
+ "right" => Label::Right,
915
+ "datapoint" => Label::DataPoint,
916
+ v => {
917
+ return Err(RbValueError::new_err(format!(
918
+ "`label` must be one of {{'left', 'right', 'datapoint'}}, got {v}",
919
+ )))
920
+ }
921
+ };
922
+ Ok(Wrap(parsed))
923
+ }
924
+ }
925
+
898
926
  impl TryConvert for Wrap<ListToStructWidthStrategy> {
899
927
  fn try_convert(ob: Value) -> RbResult<Self> {
900
- let parsed = match ob.try_convert::<String>()?.as_str() {
928
+ let parsed = match String::try_convert(ob)?.as_str() {
901
929
  "first_non_null" => ListToStructWidthStrategy::FirstNonNull,
902
930
  "max_width" => ListToStructWidthStrategy::MaxWidth,
903
931
  v => {
@@ -913,7 +941,7 @@ impl TryConvert for Wrap<ListToStructWidthStrategy> {
913
941
 
914
942
  impl TryConvert for Wrap<NullBehavior> {
915
943
  fn try_convert(ob: Value) -> RbResult<Self> {
916
- let parsed = match ob.try_convert::<String>()?.as_str() {
944
+ let parsed = match String::try_convert(ob)?.as_str() {
917
945
  "drop" => NullBehavior::Drop,
918
946
  "ignore" => NullBehavior::Ignore,
919
947
  v => {
@@ -929,7 +957,7 @@ impl TryConvert for Wrap<NullBehavior> {
929
957
 
930
958
  impl TryConvert for Wrap<NullStrategy> {
931
959
  fn try_convert(ob: Value) -> RbResult<Self> {
932
- let parsed = match ob.try_convert::<String>()?.as_str() {
960
+ let parsed = match String::try_convert(ob)?.as_str() {
933
961
  "ignore" => NullStrategy::Ignore,
934
962
  "propagate" => NullStrategy::Propagate,
935
963
  v => {
@@ -945,7 +973,7 @@ impl TryConvert for Wrap<NullStrategy> {
945
973
 
946
974
  impl TryConvert for Wrap<ParallelStrategy> {
947
975
  fn try_convert(ob: Value) -> RbResult<Self> {
948
- let parsed = match ob.try_convert::<String>()?.as_str() {
976
+ let parsed = match String::try_convert(ob)?.as_str() {
949
977
  "auto" => ParallelStrategy::Auto,
950
978
  "columns" => ParallelStrategy::Columns,
951
979
  "row_groups" => ParallelStrategy::RowGroups,
@@ -963,7 +991,7 @@ impl TryConvert for Wrap<ParallelStrategy> {
963
991
 
964
992
  impl TryConvert for Wrap<QuantileInterpolOptions> {
965
993
  fn try_convert(ob: Value) -> RbResult<Self> {
966
- let parsed = match ob.try_convert::<String>()?.as_str() {
994
+ let parsed = match String::try_convert(ob)?.as_str() {
967
995
  "lower" => QuantileInterpolOptions::Lower,
968
996
  "higher" => QuantileInterpolOptions::Higher,
969
997
  "nearest" => QuantileInterpolOptions::Nearest,
@@ -982,7 +1010,7 @@ impl TryConvert for Wrap<QuantileInterpolOptions> {
982
1010
 
983
1011
  impl TryConvert for Wrap<RankMethod> {
984
1012
  fn try_convert(ob: Value) -> RbResult<Self> {
985
- let parsed = match ob.try_convert::<String>()?.as_str() {
1013
+ let parsed = match String::try_convert(ob)?.as_str() {
986
1014
  "min" => RankMethod::Min,
987
1015
  "max" => RankMethod::Max,
988
1016
  "average" => RankMethod::Average,
@@ -1002,7 +1030,7 @@ impl TryConvert for Wrap<RankMethod> {
1002
1030
 
1003
1031
  impl TryConvert for Wrap<TimeUnit> {
1004
1032
  fn try_convert(ob: Value) -> RbResult<Self> {
1005
- let parsed = match ob.try_convert::<String>()?.as_str() {
1033
+ let parsed = match String::try_convert(ob)?.as_str() {
1006
1034
  "ns" => TimeUnit::Nanoseconds,
1007
1035
  "us" => TimeUnit::Microseconds,
1008
1036
  "ms" => TimeUnit::Milliseconds,
@@ -1019,7 +1047,7 @@ impl TryConvert for Wrap<TimeUnit> {
1019
1047
 
1020
1048
  impl TryConvert for Wrap<UniqueKeepStrategy> {
1021
1049
  fn try_convert(ob: Value) -> RbResult<Self> {
1022
- let parsed = match ob.try_convert::<String>()?.as_str() {
1050
+ let parsed = match String::try_convert(ob)?.as_str() {
1023
1051
  "first" => UniqueKeepStrategy::First,
1024
1052
  "last" => UniqueKeepStrategy::Last,
1025
1053
  v => {
@@ -1035,7 +1063,7 @@ impl TryConvert for Wrap<UniqueKeepStrategy> {
1035
1063
 
1036
1064
  impl TryConvert for Wrap<SearchSortedSide> {
1037
1065
  fn try_convert(ob: Value) -> RbResult<Self> {
1038
- let parsed = match ob.try_convert::<String>()?.as_str() {
1066
+ let parsed = match String::try_convert(ob)?.as_str() {
1039
1067
  "any" => SearchSortedSide::Any,
1040
1068
  "left" => SearchSortedSide::Left,
1041
1069
  "right" => SearchSortedSide::Right,