polars-df 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,