polars-df 0.21.1 → 0.23.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Cargo.lock +120 -90
  4. data/Cargo.toml +3 -0
  5. data/README.md +20 -7
  6. data/ext/polars/Cargo.toml +18 -12
  7. data/ext/polars/src/batched_csv.rs +4 -4
  8. data/ext/polars/src/catalog/unity.rs +96 -94
  9. data/ext/polars/src/conversion/any_value.rs +39 -37
  10. data/ext/polars/src/conversion/chunked_array.rs +36 -29
  11. data/ext/polars/src/conversion/datetime.rs +11 -0
  12. data/ext/polars/src/conversion/mod.rs +244 -51
  13. data/ext/polars/src/dataframe/construction.rs +5 -17
  14. data/ext/polars/src/dataframe/export.rs +17 -15
  15. data/ext/polars/src/dataframe/general.rs +15 -17
  16. data/ext/polars/src/dataframe/io.rs +1 -2
  17. data/ext/polars/src/dataframe/mod.rs +25 -1
  18. data/ext/polars/src/dataframe/serde.rs +23 -8
  19. data/ext/polars/src/exceptions.rs +8 -5
  20. data/ext/polars/src/expr/datatype.rs +4 -4
  21. data/ext/polars/src/expr/datetime.rs +22 -28
  22. data/ext/polars/src/expr/general.rs +3 -10
  23. data/ext/polars/src/expr/list.rs +8 -24
  24. data/ext/polars/src/expr/meta.rs +4 -6
  25. data/ext/polars/src/expr/mod.rs +2 -0
  26. data/ext/polars/src/expr/name.rs +11 -14
  27. data/ext/polars/src/expr/serde.rs +28 -0
  28. data/ext/polars/src/expr/string.rs +5 -10
  29. data/ext/polars/src/file.rs +20 -14
  30. data/ext/polars/src/functions/business.rs +0 -1
  31. data/ext/polars/src/functions/io.rs +7 -4
  32. data/ext/polars/src/functions/lazy.rs +7 -6
  33. data/ext/polars/src/functions/meta.rs +3 -3
  34. data/ext/polars/src/functions/string_cache.rs +3 -3
  35. data/ext/polars/src/interop/arrow/to_ruby.rs +3 -3
  36. data/ext/polars/src/interop/numo/numo_rs.rs +4 -3
  37. data/ext/polars/src/io/mod.rs +23 -3
  38. data/ext/polars/src/lazyframe/general.rs +35 -50
  39. data/ext/polars/src/lazyframe/mod.rs +16 -1
  40. data/ext/polars/src/lazyframe/optflags.rs +57 -0
  41. data/ext/polars/src/lazyframe/serde.rs +27 -3
  42. data/ext/polars/src/lib.rs +144 -19
  43. data/ext/polars/src/map/dataframe.rs +18 -15
  44. data/ext/polars/src/map/lazy.rs +6 -5
  45. data/ext/polars/src/map/series.rs +7 -6
  46. data/ext/polars/src/on_startup.rs +12 -5
  47. data/ext/polars/src/rb_modules.rs +2 -2
  48. data/ext/polars/src/series/aggregation.rs +49 -29
  49. data/ext/polars/src/series/construction.rs +2 -0
  50. data/ext/polars/src/series/export.rs +38 -33
  51. data/ext/polars/src/series/general.rs +69 -31
  52. data/ext/polars/src/series/mod.rs +29 -4
  53. data/lib/polars/array_expr.rb +1 -1
  54. data/lib/polars/data_frame.rb +119 -15
  55. data/lib/polars/data_types.rb +23 -6
  56. data/lib/polars/date_time_expr.rb +36 -15
  57. data/lib/polars/expr.rb +41 -32
  58. data/lib/polars/functions/business.rb +95 -0
  59. data/lib/polars/functions/lazy.rb +1 -1
  60. data/lib/polars/iceberg_dataset.rb +113 -0
  61. data/lib/polars/io/iceberg.rb +34 -0
  62. data/lib/polars/io/ipc.rb +28 -49
  63. data/lib/polars/io/parquet.rb +7 -4
  64. data/lib/polars/io/scan_options.rb +12 -3
  65. data/lib/polars/io/utils.rb +17 -0
  66. data/lib/polars/lazy_frame.rb +97 -10
  67. data/lib/polars/list_expr.rb +21 -13
  68. data/lib/polars/list_name_space.rb +33 -21
  69. data/lib/polars/meta_expr.rb +25 -0
  70. data/lib/polars/query_opt_flags.rb +50 -0
  71. data/lib/polars/scan_cast_options.rb +23 -1
  72. data/lib/polars/schema.rb +1 -1
  73. data/lib/polars/selectors.rb +8 -8
  74. data/lib/polars/series.rb +26 -2
  75. data/lib/polars/string_expr.rb +27 -28
  76. data/lib/polars/string_name_space.rb +18 -5
  77. data/lib/polars/utils/convert.rb +2 -2
  78. data/lib/polars/utils/serde.rb +17 -0
  79. data/lib/polars/utils/various.rb +4 -0
  80. data/lib/polars/version.rb +1 -1
  81. data/lib/polars.rb +6 -0
  82. metadata +10 -1
@@ -1,10 +1,10 @@
1
1
  [package]
2
2
  name = "polars"
3
- version = "0.21.1"
3
+ version = "0.23.0"
4
4
  license = "MIT"
5
5
  authors = ["Andrew Kane <andrew@ankane.org>"]
6
6
  edition = "2024"
7
- rust-version = "1.85.0"
7
+ rust-version = "1.89.0"
8
8
  publish = false
9
9
 
10
10
  [lib]
@@ -12,25 +12,27 @@ crate-type = ["cdylib"]
12
12
 
13
13
  [dependencies]
14
14
  ahash = "0.8"
15
- arrow = { package = "polars-arrow", version = "=0.50.0" }
15
+ arrow = { package = "polars-arrow", version = "=0.52.0" }
16
16
  bytes = "1"
17
17
  chrono = "0.4"
18
18
  either = "1.8"
19
- magnus = { git = "https://github.com/matsadler/magnus.git", rev = "4125ee2ab5a405d17aa6d7503961c1ecdbe499ef", features = ["chrono"] }
19
+ magnus = { version = "0.8", features = ["chrono"] }
20
20
  num-traits = "0.2"
21
- polars-core = "=0.50.0"
22
- polars-dtype = "=0.50.0"
23
- polars-io = "=0.50.0"
24
- polars-lazy = { version = "=0.50.0", features = ["catalog"] }
25
- polars-plan = "=0.50.0"
26
- polars-parquet = "=0.50.0"
27
- polars-utils = "=0.50.0"
21
+ polars-compute = "=0.52.0"
22
+ polars-core = "=0.52.0"
23
+ polars-dtype = "=0.52.0"
24
+ polars-error = "=0.52.0"
25
+ polars-io = "=0.52.0"
26
+ polars-lazy = { version = "=0.52.0", features = ["catalog"] }
27
+ polars-plan = "=0.52.0"
28
+ polars-parquet = "=0.52.0"
29
+ polars-utils = "=0.52.0"
28
30
  rayon = "1.9"
29
31
  regex = "1"
30
32
  serde_json = "1"
31
33
 
32
34
  [dependencies.polars]
33
- version = "=0.50.0"
35
+ version = "=0.52.0"
34
36
  features = [
35
37
  "abs",
36
38
  "approx_unique",
@@ -141,3 +143,7 @@ jemallocator = { version = "0.5", features = ["disable_initial_exec_tls"] }
141
143
 
142
144
  [target.'cfg(not(any(target_os = "linux", target_os = "windows")))'.dependencies]
143
145
  mimalloc = { version = "0.1", default-features = false }
146
+
147
+ [features]
148
+ default = []
149
+ serialize_binary = []
@@ -2,7 +2,7 @@ use std::cell::RefCell;
2
2
  use std::path::PathBuf;
3
3
  use std::sync::Mutex;
4
4
 
5
- use magnus::{RArray, Value, prelude::*};
5
+ use magnus::{RArray, Ruby, Value, prelude::*};
6
6
  use polars::io::RowIndex;
7
7
  use polars::io::csv::read::OwnedBatchedCsvReader;
8
8
  use polars::io::mmap::MmapBytesReader;
@@ -124,8 +124,8 @@ impl RbBatchedCsv {
124
124
  })
125
125
  }
126
126
 
127
- pub fn next_batches(&self, n: usize) -> RbResult<Option<RArray>> {
128
- let reader = &self.reader;
127
+ pub fn next_batches(ruby: &Ruby, rb_self: &Self, n: usize) -> RbResult<Option<RArray>> {
128
+ let reader = &rb_self.reader;
129
129
  let batches = reader
130
130
  .borrow()
131
131
  .lock()
@@ -133,6 +133,6 @@ impl RbBatchedCsv {
133
133
  .next_batches(n)
134
134
  .map_err(RbPolarsErr::from)?;
135
135
 
136
- Ok(batches.map(|batches| RArray::from_iter(batches.into_iter().map(RbDataFrame::from))))
136
+ Ok(batches.map(|batches| ruby.ary_from_iter(batches.into_iter().map(RbDataFrame::from))))
137
137
  }
138
138
  }
@@ -1,7 +1,7 @@
1
1
  use std::str::FromStr;
2
2
 
3
3
  use magnus::value::{Lazy, ReprValue};
4
- use magnus::{IntoValue, Module, RArray, RClass, RHash, RModule, Ruby, Value};
4
+ use magnus::{IntoValue, Module, RClass, RHash, RModule, Ruby, Value};
5
5
  use polars::prelude::{PlHashMap, PlSmallStr, Schema};
6
6
  use polars_io::catalog::unity::client::{CatalogClient, CatalogClientBuilder};
7
7
  use polars_io::catalog::unity::models::{
@@ -85,15 +85,15 @@ impl RbCatalogClient {
85
85
  builder.build().map(RbCatalogClient).map_err(to_rb_err)
86
86
  }
87
87
 
88
- pub fn list_catalogs(&self) -> RbResult<Value> {
88
+ pub fn list_catalogs(ruby: &Ruby, rb_self: &Self) -> RbResult<Value> {
89
89
  let v = pl_async::get_runtime()
90
- .block_in_place_on(self.client().list_catalogs())
90
+ .block_in_place_on(rb_self.client().list_catalogs())
91
91
  .map_err(to_rb_err)?;
92
92
 
93
93
  let mut opt_err = None;
94
94
 
95
- let out = RArray::from_iter(v.into_iter().map(|x| {
96
- let v = catalog_info_to_rbobject(x);
95
+ let out = ruby.ary_from_iter(v.into_iter().map(|x| {
96
+ let v = catalog_info_to_rbobject(ruby, x);
97
97
  if let Ok(v) = v {
98
98
  Some(v)
99
99
  } else {
@@ -104,18 +104,18 @@ impl RbCatalogClient {
104
104
 
105
105
  opt_err.transpose()?;
106
106
 
107
- Ok(out.into_value())
107
+ Ok(out.as_value())
108
108
  }
109
109
 
110
- pub fn list_namespaces(&self, catalog_name: String) -> RbResult<Value> {
110
+ pub fn list_namespaces(ruby: &Ruby, rb_self: &Self, catalog_name: String) -> RbResult<Value> {
111
111
  let v = pl_async::get_runtime()
112
- .block_in_place_on(self.client().list_namespaces(&catalog_name))
112
+ .block_in_place_on(rb_self.client().list_namespaces(&catalog_name))
113
113
  .map_err(to_rb_err)?;
114
114
 
115
115
  let mut opt_err = None;
116
116
 
117
- let out = RArray::from_iter(v.into_iter().map(|x| {
118
- let v = namespace_info_to_rbobject(x);
117
+ let out = ruby.ary_from_iter(v.into_iter().map(|x| {
118
+ let v = namespace_info_to_rbobject(ruby, x);
119
119
  match v {
120
120
  Ok(v) => Some(v),
121
121
  Err(_) => {
@@ -127,27 +127,33 @@ impl RbCatalogClient {
127
127
 
128
128
  opt_err.transpose()?;
129
129
 
130
- Ok(out.into_value())
130
+ Ok(out.as_value())
131
131
  }
132
132
 
133
- pub fn list_tables(&self, catalog_name: String, namespace: String) -> RbResult<Value> {
133
+ pub fn list_tables(
134
+ ruby: &Ruby,
135
+ rb_self: &Self,
136
+ catalog_name: String,
137
+ namespace: String,
138
+ ) -> RbResult<Value> {
134
139
  let v = pl_async::get_runtime()
135
- .block_in_place_on(self.client().list_tables(&catalog_name, &namespace))
140
+ .block_in_place_on(rb_self.client().list_tables(&catalog_name, &namespace))
136
141
  .map_err(to_rb_err)?;
137
142
 
138
143
  let mut opt_err = None;
139
144
 
140
- let out = RArray::from_iter(v.into_iter().map(|table_info| {
141
- let v = table_info_to_rbobject(table_info);
145
+ let out = ruby
146
+ .ary_from_iter(v.into_iter().map(|table_info| {
147
+ let v = table_info_to_rbobject(ruby, table_info);
142
148
 
143
- if let Ok(v) = v {
144
- Some(v)
145
- } else {
146
- opt_err.replace(v);
147
- None
148
- }
149
- }))
150
- .into_value();
149
+ if let Ok(v) = v {
150
+ Some(v)
151
+ } else {
152
+ opt_err.replace(v);
153
+ None
154
+ }
155
+ }))
156
+ .as_value();
151
157
 
152
158
  opt_err.transpose()?;
153
159
 
@@ -155,36 +161,39 @@ impl RbCatalogClient {
155
161
  }
156
162
 
157
163
  pub fn get_table_info(
158
- &self,
164
+ ruby: &Ruby,
165
+ rb_self: &Self,
159
166
  table_name: String,
160
167
  catalog_name: String,
161
168
  namespace: String,
162
169
  ) -> RbResult<Value> {
163
170
  let table_info = pl_async::get_runtime()
164
- .block_in_place_on(
165
- self.client()
166
- .get_table_info(&table_name, &catalog_name, &namespace),
167
- )
171
+ .block_in_place_on(rb_self.client().get_table_info(
172
+ &table_name,
173
+ &catalog_name,
174
+ &namespace,
175
+ ))
168
176
  .map_err(to_rb_err)?;
169
177
 
170
- table_info_to_rbobject(table_info)
178
+ table_info_to_rbobject(ruby, table_info)
171
179
  }
172
180
 
173
181
  pub fn create_catalog(
174
- &self,
182
+ ruby: &Ruby,
183
+ rb_self: &Self,
175
184
  catalog_name: String,
176
185
  comment: Option<String>,
177
186
  storage_root: Option<String>,
178
187
  ) -> RbResult<Value> {
179
188
  let catalog_info = pl_async::get_runtime()
180
- .block_in_place_on(self.client().create_catalog(
189
+ .block_in_place_on(rb_self.client().create_catalog(
181
190
  &catalog_name,
182
191
  comment.as_deref(),
183
192
  storage_root.as_deref(),
184
193
  ))
185
194
  .map_err(to_rb_err)?;
186
195
 
187
- catalog_info_to_rbobject(catalog_info)
196
+ catalog_info_to_rbobject(ruby, catalog_info)
188
197
  }
189
198
 
190
199
  pub fn delete_catalog(&self, catalog_name: String, force: bool) -> RbResult<()> {
@@ -194,14 +203,15 @@ impl RbCatalogClient {
194
203
  }
195
204
 
196
205
  pub fn create_namespace(
197
- &self,
206
+ ruby: &Ruby,
207
+ rb_self: &Self,
198
208
  catalog_name: String,
199
209
  namespace: String,
200
210
  comment: Option<String>,
201
211
  storage_root: Option<String>,
202
212
  ) -> RbResult<Value> {
203
213
  let namespace_info = pl_async::get_runtime()
204
- .block_in_place_on(self.client().create_namespace(
214
+ .block_in_place_on(rb_self.client().create_namespace(
205
215
  &catalog_name,
206
216
  &namespace,
207
217
  comment.as_deref(),
@@ -209,7 +219,7 @@ impl RbCatalogClient {
209
219
  ))
210
220
  .map_err(to_rb_err)?;
211
221
 
212
- namespace_info_to_rbobject(namespace_info)
222
+ namespace_info_to_rbobject(ruby, namespace_info)
213
223
  }
214
224
 
215
225
  pub fn delete_namespace(
@@ -228,7 +238,8 @@ impl RbCatalogClient {
228
238
 
229
239
  #[allow(clippy::too_many_arguments)]
230
240
  pub fn create_table(
231
- &self,
241
+ ruby: &Ruby,
242
+ rb_self: &Self,
232
243
  catalog_name: String,
233
244
  namespace: String,
234
245
  table_name: String,
@@ -241,7 +252,7 @@ impl RbCatalogClient {
241
252
  ) -> RbResult<Value> {
242
253
  let table_info = pl_async::get_runtime()
243
254
  .block_in_place_on(
244
- self.client().create_table(
255
+ rb_self.client().create_table(
245
256
  &catalog_name,
246
257
  &namespace,
247
258
  &table_name,
@@ -261,7 +272,7 @@ impl RbCatalogClient {
261
272
  )
262
273
  .map_err(to_rb_err)?;
263
274
 
264
- table_info_to_rbobject(table_info)
275
+ table_info_to_rbobject(ruby, table_info)
265
276
  }
266
277
 
267
278
  pub fn delete_table(
@@ -278,8 +289,8 @@ impl RbCatalogClient {
278
289
  .map_err(to_rb_err)
279
290
  }
280
291
 
281
- pub fn type_json_to_polars_type(type_json: String) -> RbResult<Value> {
282
- Ok(Wrap(parse_type_json_str(&type_json).map_err(to_rb_err)?).into_value())
292
+ pub fn type_json_to_polars_type(ruby: &Ruby, type_json: String) -> RbResult<Value> {
293
+ Ok(Wrap(parse_type_json_str(&type_json).map_err(to_rb_err)?).into_value_with(ruby))
283
294
  }
284
295
  }
285
296
 
@@ -290,6 +301,7 @@ impl RbCatalogClient {
290
301
  }
291
302
 
292
303
  fn catalog_info_to_rbobject(
304
+ ruby: &Ruby,
293
305
  CatalogInfo {
294
306
  name,
295
307
  comment,
@@ -302,10 +314,10 @@ fn catalog_info_to_rbobject(
302
314
  updated_by,
303
315
  }: CatalogInfo,
304
316
  ) -> RbResult<Value> {
305
- let dict = RHash::new();
317
+ let dict = ruby.hash_new();
306
318
 
307
- let properties = properties_to_rbobject(properties);
308
- let options = properties_to_rbobject(options);
319
+ let properties = properties_to_rbobject(ruby, properties);
320
+ let options = properties_to_rbobject(ruby, options);
309
321
 
310
322
  rbdict_insert_keys!(dict, {
311
323
  name,
@@ -319,13 +331,11 @@ fn catalog_info_to_rbobject(
319
331
  updated_by
320
332
  });
321
333
 
322
- Ruby::get()
323
- .unwrap()
324
- .get_inner(&CATALOG_INFO_CLS)
325
- .funcall("new", (dict,))
334
+ ruby.get_inner(&CATALOG_INFO_CLS).funcall("new", (dict,))
326
335
  }
327
336
 
328
337
  fn namespace_info_to_rbobject(
338
+ ruby: &Ruby,
329
339
  NamespaceInfo {
330
340
  name,
331
341
  comment,
@@ -337,9 +347,9 @@ fn namespace_info_to_rbobject(
337
347
  updated_by,
338
348
  }: NamespaceInfo,
339
349
  ) -> RbResult<Value> {
340
- let dict = RHash::new();
350
+ let dict = ruby.hash_new();
341
351
 
342
- let properties = properties_to_rbobject(properties);
352
+ let properties = properties_to_rbobject(ruby, properties);
343
353
 
344
354
  rbdict_insert_keys!(dict, {
345
355
  name,
@@ -352,13 +362,10 @@ fn namespace_info_to_rbobject(
352
362
  updated_by
353
363
  });
354
364
 
355
- Ruby::get()
356
- .unwrap()
357
- .get_inner(&NAMESPACE_INFO_CLS)
358
- .funcall("new", (dict,))
365
+ ruby.get_inner(&NAMESPACE_INFO_CLS).funcall("new", (dict,))
359
366
  }
360
367
 
361
- fn table_info_to_rbobject(table_info: TableInfo) -> RbResult<Value> {
368
+ fn table_info_to_rbobject(ruby: &Ruby, table_info: TableInfo) -> RbResult<Value> {
362
369
  let TableInfo {
363
370
  name,
364
371
  table_id,
@@ -374,49 +381,47 @@ fn table_info_to_rbobject(table_info: TableInfo) -> RbResult<Value> {
374
381
  updated_by,
375
382
  } = table_info;
376
383
 
377
- let column_info_cls = Ruby::get().unwrap().get_inner(&COLUMN_INFO_CLS);
384
+ let column_info_cls = ruby.get_inner(&COLUMN_INFO_CLS);
378
385
 
379
386
  let columns = columns
380
387
  .map(|columns| {
381
- Ruby::get()
382
- .unwrap()
383
- .ary_try_from_iter(columns.into_iter().map(
384
- |ColumnInfo {
385
- name,
386
- type_name,
387
- type_text,
388
- type_json,
389
- position,
390
- comment,
391
- partition_index,
392
- }| {
393
- let dict = RHash::new();
394
-
395
- let name = name.as_str();
396
- let type_name = type_name.as_str();
397
- let type_text = type_text.as_str();
398
-
399
- rbdict_insert_keys!(dict, {
400
- name,
401
- type_name,
402
- type_text,
403
- type_json,
404
- position,
405
- comment,
406
- partition_index,
407
- });
408
-
409
- column_info_cls.funcall::<_, _, Value>("new", (dict,))
410
- },
411
- ))
388
+ ruby.ary_try_from_iter(columns.into_iter().map(
389
+ |ColumnInfo {
390
+ name,
391
+ type_name,
392
+ type_text,
393
+ type_json,
394
+ position,
395
+ comment,
396
+ partition_index,
397
+ }| {
398
+ let dict = ruby.hash_new();
399
+
400
+ let name = name.as_str();
401
+ let type_name = type_name.as_str();
402
+ let type_text = type_text.as_str();
403
+
404
+ rbdict_insert_keys!(dict, {
405
+ name,
406
+ type_name,
407
+ type_text,
408
+ type_json,
409
+ position,
410
+ comment,
411
+ partition_index,
412
+ });
413
+
414
+ column_info_cls.funcall::<_, _, Value>("new", (dict,))
415
+ },
416
+ ))
412
417
  })
413
418
  .transpose()?;
414
419
 
415
- let dict = RHash::new();
420
+ let dict = ruby.hash_new();
416
421
 
417
422
  let data_source_format = data_source_format.map(|x| x.to_string());
418
423
  let table_type = table_type.to_string();
419
- let properties = properties_to_rbobject(properties);
424
+ let properties = properties_to_rbobject(ruby, properties);
420
425
 
421
426
  rbdict_insert_keys!(dict, {
422
427
  name,
@@ -433,14 +438,11 @@ fn table_info_to_rbobject(table_info: TableInfo) -> RbResult<Value> {
433
438
  updated_by,
434
439
  });
435
440
 
436
- Ruby::get()
437
- .unwrap()
438
- .get_inner(&TABLE_INFO_CLS)
439
- .funcall("new", (dict,))
441
+ ruby.get_inner(&TABLE_INFO_CLS).funcall("new", (dict,))
440
442
  }
441
443
 
442
- fn properties_to_rbobject(properties: PlHashMap<PlSmallStr, String>) -> RHash {
443
- let dict = RHash::new();
444
+ fn properties_to_rbobject(ruby: &Ruby, properties: PlHashMap<PlSmallStr, String>) -> RHash {
445
+ let dict = ruby.hash_new();
444
446
 
445
447
  for (key, value) in properties.into_iter() {
446
448
  dict.aset(key.as_str(), value).unwrap();
@@ -1,14 +1,16 @@
1
- use magnus::encoding::{EncodingCapable, Index};
1
+ use magnus::encoding::EncodingCapable;
2
2
  use magnus::{
3
- IntoValue, RArray, RHash, RString, Ruby, TryConvert, Value, class, prelude::*, r_hash::ForEach,
3
+ IntoValue, RArray, RHash, RString, Ruby, TryConvert, Value, prelude::*, r_hash::ForEach,
4
4
  };
5
5
  use polars::prelude::*;
6
+ use polars_compute::decimal::{DEC128_MAX_PREC, DecimalFmtBuffer, dec128_fits};
6
7
  use polars_core::utils::any_values_to_supertype_and_n_dtypes;
7
8
 
9
+ use super::datetime::datetime_to_rb_object;
8
10
  use super::{ObjectValue, Wrap, struct_dict};
9
11
 
10
12
  use crate::exceptions::RbOverflowError;
11
- use crate::rb_modules::utils;
13
+ use crate::rb_modules::pl_utils;
12
14
  use crate::{RbErr, RbPolarsErr, RbResult, RbSeries};
13
15
 
14
16
  impl IntoValue for Wrap<AnyValue<'_>> {
@@ -29,11 +31,12 @@ pub(crate) fn any_value_into_rb_object(av: AnyValue, ruby: &Ruby) -> Value {
29
31
  AnyValue::UInt16(v) => ruby.into_value(v),
30
32
  AnyValue::UInt32(v) => ruby.into_value(v),
31
33
  AnyValue::UInt64(v) => ruby.into_value(v),
34
+ AnyValue::UInt128(v) => ruby.into_value(v),
32
35
  AnyValue::Int8(v) => ruby.into_value(v),
33
36
  AnyValue::Int16(v) => ruby.into_value(v),
34
37
  AnyValue::Int32(v) => ruby.into_value(v),
35
38
  AnyValue::Int64(v) => ruby.into_value(v),
36
- AnyValue::Int128(_v) => todo!(),
39
+ AnyValue::Int128(v) => ruby.into_value(v),
37
40
  AnyValue::Float32(v) => ruby.into_value(v),
38
41
  AnyValue::Float64(v) => ruby.into_value(v),
39
42
  AnyValue::Null => ruby.qnil().as_value(),
@@ -41,12 +44,12 @@ pub(crate) fn any_value_into_rb_object(av: AnyValue, ruby: &Ruby) -> Value {
41
44
  AnyValue::String(v) => ruby.into_value(v),
42
45
  AnyValue::StringOwned(v) => ruby.into_value(v.as_str()),
43
46
  AnyValue::Categorical(cat, map) | AnyValue::Enum(cat, map) => unsafe {
44
- map.cat_to_str_unchecked(cat).into_value()
47
+ map.cat_to_str_unchecked(cat).into_value_with(ruby)
45
48
  },
46
49
  AnyValue::CategoricalOwned(cat, map) | AnyValue::EnumOwned(cat, map) => unsafe {
47
- map.cat_to_str_unchecked(cat).into_value()
50
+ map.cat_to_str_unchecked(cat).into_value_with(ruby)
48
51
  },
49
- AnyValue::Date(v) => utils().funcall("_to_ruby_date", (v,)).unwrap(),
52
+ AnyValue::Date(v) => pl_utils().funcall("_to_ruby_date", (v,)).unwrap(),
50
53
  AnyValue::Datetime(v, time_unit, time_zone) => {
51
54
  datetime_to_rb_object(v, time_unit, time_zone)
52
55
  }
@@ -55,14 +58,14 @@ pub(crate) fn any_value_into_rb_object(av: AnyValue, ruby: &Ruby) -> Value {
55
58
  }
56
59
  AnyValue::Duration(v, time_unit) => {
57
60
  let time_unit = time_unit.to_ascii();
58
- utils()
61
+ pl_utils()
59
62
  .funcall("_to_ruby_duration", (v, time_unit))
60
63
  .unwrap()
61
64
  }
62
- AnyValue::Time(v) => utils().funcall("_to_ruby_time", (v,)).unwrap(),
63
- AnyValue::Array(v, _) | AnyValue::List(v) => RbSeries::new(v).to_a().into_value(),
64
- ref av @ AnyValue::Struct(_, _, flds) => struct_dict(av._iter_struct_av(), flds),
65
- AnyValue::StructOwned(payload) => struct_dict(payload.0.into_iter(), &payload.1),
65
+ AnyValue::Time(v) => pl_utils().funcall("_to_ruby_time", (v,)).unwrap(),
66
+ AnyValue::Array(v, _) | AnyValue::List(v) => RbSeries::new(v).to_a().as_value(),
67
+ ref av @ AnyValue::Struct(_, _, flds) => struct_dict(ruby, av._iter_struct_av(), flds),
68
+ AnyValue::StructOwned(payload) => struct_dict(ruby, payload.0.into_iter(), &payload.1),
66
69
  AnyValue::Object(v) => {
67
70
  let object = v.as_any().downcast_ref::<ObjectValue>().unwrap();
68
71
  object.to_value()
@@ -71,21 +74,16 @@ pub(crate) fn any_value_into_rb_object(av: AnyValue, ruby: &Ruby) -> Value {
71
74
  let object = v.0.as_any().downcast_ref::<ObjectValue>().unwrap();
72
75
  object.to_value()
73
76
  }
74
- AnyValue::Binary(v) => RString::from_slice(v).into_value(),
75
- AnyValue::BinaryOwned(v) => RString::from_slice(&v).into_value(),
76
- AnyValue::Decimal(v, scale) => utils()
77
- .funcall("_to_ruby_decimal", (v.to_string(), -(scale as i32)))
78
- .unwrap(),
77
+ AnyValue::Binary(v) => ruby.str_from_slice(v).as_value(),
78
+ AnyValue::BinaryOwned(v) => ruby.str_from_slice(&v).as_value(),
79
+ AnyValue::Decimal(v, prec, scale) => {
80
+ let mut buf = DecimalFmtBuffer::new();
81
+ let s = buf.format_dec128(v, scale, false, false);
82
+ pl_utils().funcall("_to_ruby_decimal", (prec, s)).unwrap()
83
+ }
79
84
  }
80
85
  }
81
86
 
82
- fn datetime_to_rb_object(v: i64, tu: TimeUnit, tz: Option<&TimeZone>) -> Value {
83
- let tu = tu.to_ascii();
84
- utils()
85
- .funcall("_to_ruby_datetime", (v, tu, tz.map(|v| v.to_string())))
86
- .unwrap()
87
- }
88
-
89
87
  pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<AnyValue<'s>> {
90
88
  // Conversion functions.
91
89
  fn get_null(_ob: Value, _strict: bool) -> RbResult<AnyValue<'static>> {
@@ -100,8 +98,12 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
100
98
  fn get_int(ob: Value, strict: bool) -> RbResult<AnyValue<'static>> {
101
99
  if let Ok(v) = i64::try_convert(ob) {
102
100
  Ok(AnyValue::Int64(v))
101
+ } else if let Ok(v) = i128::try_convert(ob) {
102
+ Ok(AnyValue::Int128(v))
103
103
  } else if let Ok(v) = u64::try_convert(ob) {
104
104
  Ok(AnyValue::UInt64(v))
105
+ } else if let Ok(v) = u128::try_convert(ob) {
106
+ Ok(AnyValue::UInt128(v))
105
107
  } else if !strict {
106
108
  let f = f64::try_convert(ob)?;
107
109
  Ok(AnyValue::Float64(f))
@@ -117,8 +119,9 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
117
119
  }
118
120
 
119
121
  fn get_str(ob: Value, _strict: bool) -> RbResult<AnyValue<'static>> {
122
+ let ruby = Ruby::get_with(ob);
120
123
  let v = RString::from_value(ob).unwrap();
121
- if v.enc_get() == Index::utf8() {
124
+ if v.enc_get() == ruby.utf8_encindex() {
122
125
  Ok(AnyValue::StringOwned(v.to_string()?.into()))
123
126
  } else {
124
127
  Ok(AnyValue::BinaryOwned(unsafe { v.as_slice() }.to_vec()))
@@ -211,14 +214,12 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
211
214
  match digits.parse::<i128>() {
212
215
  Ok(mut v) => {
213
216
  let scale = if exp > 0 {
214
- v = 10_i128
215
- .checked_pow(exp as u32)
216
- .and_then(|factor| v.checked_mul(factor))?;
217
+ v = 10_i128.checked_pow(exp as u32)?.checked_mul(v)?;
217
218
  0
218
219
  } else {
219
220
  (-exp) as usize
220
221
  };
221
- Some((v, scale))
222
+ dec128_fits(v, DEC128_MAX_PREC).then_some((v, scale))
222
223
  }
223
224
  Err(_) => None,
224
225
  }
@@ -234,27 +235,28 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
234
235
  // TODO better error
235
236
  v = v.checked_neg().unwrap();
236
237
  }
237
- Ok(AnyValue::Decimal(v, scale))
238
+ Ok(AnyValue::Decimal(v, DEC128_MAX_PREC, scale))
238
239
  }
239
240
 
241
+ let ruby = Ruby::get_with(ob);
240
242
  if ob.is_nil() {
241
243
  get_null(ob, strict)
242
- } else if ob.is_kind_of(class::true_class()) || ob.is_kind_of(class::false_class()) {
244
+ } else if ob.is_kind_of(ruby.class_true_class()) || ob.is_kind_of(ruby.class_false_class()) {
243
245
  get_bool(ob, strict)
244
- } else if ob.is_kind_of(class::integer()) {
246
+ } else if ob.is_kind_of(ruby.class_integer()) {
245
247
  get_int(ob, strict)
246
- } else if ob.is_kind_of(class::float()) {
248
+ } else if ob.is_kind_of(ruby.class_float()) {
247
249
  get_float(ob, strict)
248
- } else if ob.is_kind_of(class::string()) {
250
+ } else if ob.is_kind_of(ruby.class_string()) {
249
251
  get_str(ob, strict)
250
- } else if ob.is_kind_of(class::array()) {
252
+ } else if ob.is_kind_of(ruby.class_array()) {
251
253
  get_list(ob, strict)
252
- } else if ob.is_kind_of(class::hash()) {
254
+ } else if ob.is_kind_of(ruby.class_hash()) {
253
255
  get_struct(ob, strict)
254
256
  } else if ob.respond_to("_s", true)? {
255
257
  get_list_from_series(ob, strict)
256
258
  // call is_a? for ActiveSupport::TimeWithZone
257
- } else if ob.funcall::<_, _, bool>("is_a?", (class::time(),))? {
259
+ } else if ob.funcall::<_, _, bool>("is_a?", (ruby.class_time(),))? {
258
260
  get_time(ob, strict)
259
261
  } else if ob.is_kind_of(crate::rb_modules::datetime()) {
260
262
  get_datetime(ob, strict)