polars-df 0.17.0 → 0.18.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/Cargo.lock +668 -377
- data/README.md +2 -2
- data/ext/polars/Cargo.toml +10 -8
- data/ext/polars/src/conversion/any_value.rs +1 -1
- data/ext/polars/src/conversion/mod.rs +38 -5
- data/ext/polars/src/dataframe/export.rs +2 -2
- data/ext/polars/src/dataframe/general.rs +9 -6
- data/ext/polars/src/expr/general.rs +16 -14
- data/ext/polars/src/expr/rolling.rs +17 -2
- data/ext/polars/src/file.rs +56 -14
- data/ext/polars/src/functions/lazy.rs +30 -2
- data/ext/polars/src/interop/numo/mod.rs +1 -0
- data/ext/polars/src/interop/numo/numo_rs.rs +52 -0
- data/ext/polars/src/interop/numo/to_numo_series.rs +69 -48
- data/ext/polars/src/lazyframe/general.rs +102 -66
- data/ext/polars/src/lazyframe/mod.rs +2 -0
- data/ext/polars/src/lazyframe/sink.rs +99 -0
- data/ext/polars/src/lib.rs +11 -8
- data/ext/polars/src/map/mod.rs +1 -1
- data/ext/polars/src/map/series.rs +4 -4
- data/ext/polars/src/on_startup.rs +15 -3
- data/ext/polars/src/series/export.rs +4 -4
- data/ext/polars/src/series/general.rs +2 -2
- data/lib/polars/data_frame.rb +304 -6
- data/lib/polars/expr.rb +58 -19
- data/lib/polars/functions/eager.rb +145 -16
- data/lib/polars/io/database.rb +17 -0
- data/lib/polars/lazy_frame.rb +135 -18
- data/lib/polars/list_expr.rb +4 -7
- data/lib/polars/schema.rb +29 -0
- data/lib/polars/series.rb +36 -32
- data/lib/polars/version.rb +1 -1
- data/lib/polars.rb +1 -0
- metadata +6 -3
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Ruby Polars
|
2
2
|
|
3
|
-
|
3
|
+
🔥 Blazingly fast DataFrames for Ruby, powered by [Polars](https://github.com/pola-rs/polars)
|
4
4
|
|
5
5
|
[](https://github.com/ankane/ruby-polars/actions)
|
6
6
|
|
@@ -448,7 +448,7 @@ df.group_by("c").plot("a", "b", stacked: true)
|
|
448
448
|
|
449
449
|
## History
|
450
450
|
|
451
|
-
View the [changelog](CHANGELOG.md)
|
451
|
+
View the [changelog](https://github.com/ankane/ruby-polars/blob/master/CHANGELOG.md)
|
452
452
|
|
453
453
|
## Contributing
|
454
454
|
|
data/ext/polars/Cargo.toml
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
[package]
|
2
2
|
name = "polars"
|
3
|
-
version = "0.
|
3
|
+
version = "0.18.0"
|
4
4
|
license = "MIT"
|
5
5
|
authors = ["Andrew Kane <andrew@ankane.org>"]
|
6
6
|
edition = "2021"
|
7
|
-
rust-version = "1.
|
7
|
+
rust-version = "1.85.0"
|
8
8
|
publish = false
|
9
9
|
|
10
10
|
[lib]
|
@@ -12,21 +12,22 @@ crate-type = ["cdylib"]
|
|
12
12
|
|
13
13
|
[dependencies]
|
14
14
|
ahash = "0.8"
|
15
|
-
arrow = { package = "polars-arrow", version = "=0.
|
15
|
+
arrow = { package = "polars-arrow", version = "=0.47.1" }
|
16
16
|
bytes = "1"
|
17
17
|
chrono = "0.4"
|
18
18
|
either = "1.8"
|
19
19
|
magnus = "0.7"
|
20
|
-
|
21
|
-
polars-
|
22
|
-
polars-
|
23
|
-
polars-
|
20
|
+
num-traits = "0.2"
|
21
|
+
polars-core = "=0.47.1"
|
22
|
+
polars-plan = "=0.47.1"
|
23
|
+
polars-parquet = "=0.47.1"
|
24
|
+
polars-utils = "=0.47.1"
|
24
25
|
rayon = "1.9"
|
25
26
|
regex = "1"
|
26
27
|
serde_json = "1"
|
27
28
|
|
28
29
|
[dependencies.polars]
|
29
|
-
version = "=0.
|
30
|
+
version = "=0.47.1"
|
30
31
|
features = [
|
31
32
|
"abs",
|
32
33
|
"approx_unique",
|
@@ -63,6 +64,7 @@ features = [
|
|
63
64
|
"gcp",
|
64
65
|
"http",
|
65
66
|
"interpolate",
|
67
|
+
"interpolate_by",
|
66
68
|
"ipc",
|
67
69
|
"ipc_streaming",
|
68
70
|
"is_between",
|
@@ -21,7 +21,7 @@ use polars::prelude::*;
|
|
21
21
|
use polars::series::ops::NullBehavior;
|
22
22
|
use polars_core::utils::arrow::array::Array;
|
23
23
|
use polars_core::utils::materialize_dyn_int;
|
24
|
-
use polars_plan::
|
24
|
+
use polars_plan::dsl::ScanSources;
|
25
25
|
use polars_utils::mmap::MemSlice;
|
26
26
|
use polars_utils::total_ord::{TotalEq, TotalHash};
|
27
27
|
|
@@ -219,7 +219,7 @@ impl IntoValue for Wrap<DataType> {
|
|
219
219
|
.funcall::<_, _, Value>("new", (tu.to_ascii(),))
|
220
220
|
.unwrap()
|
221
221
|
}
|
222
|
-
DataType::Object(_
|
222
|
+
DataType::Object(_) => {
|
223
223
|
let class = pl.const_get::<_, Value>("Object").unwrap();
|
224
224
|
class.funcall("new", ()).unwrap()
|
225
225
|
}
|
@@ -332,7 +332,7 @@ impl TryConvert for Wrap<DataType> {
|
|
332
332
|
"Polars::Array" => DataType::Array(Box::new(DataType::Null), 0),
|
333
333
|
"Polars::Struct" => DataType::Struct(vec![]),
|
334
334
|
"Polars::Null" => DataType::Null,
|
335
|
-
"Polars::Object" => DataType::Object(OBJECT_NAME
|
335
|
+
"Polars::Object" => DataType::Object(OBJECT_NAME),
|
336
336
|
"Polars::Unknown" => DataType::Unknown(Default::default()),
|
337
337
|
dt => {
|
338
338
|
return Err(RbValueError::new_err(format!(
|
@@ -408,7 +408,7 @@ impl TryConvert for Wrap<DataType> {
|
|
408
408
|
DataType::Struct(fields)
|
409
409
|
}
|
410
410
|
"Polars::Null" => DataType::Null,
|
411
|
-
"Object" => DataType::Object(OBJECT_NAME
|
411
|
+
"Object" => DataType::Object(OBJECT_NAME),
|
412
412
|
"Polars::Unknown" => DataType::Unknown(Default::default()),
|
413
413
|
dt => {
|
414
414
|
return Err(RbTypeError::new_err(format!(
|
@@ -437,7 +437,7 @@ impl TryConvert for Wrap<DataType> {
|
|
437
437
|
"time" => DataType::Time,
|
438
438
|
"dur" => DataType::Duration(TimeUnit::Microseconds),
|
439
439
|
"f64" => DataType::Float64,
|
440
|
-
"obj" => DataType::Object(OBJECT_NAME
|
440
|
+
"obj" => DataType::Object(OBJECT_NAME),
|
441
441
|
"list" => DataType::List(Box::new(DataType::Boolean)),
|
442
442
|
"null" => DataType::Null,
|
443
443
|
"unk" => DataType::Unknown(Default::default()),
|
@@ -761,6 +761,21 @@ impl TryConvert for Wrap<ClosedWindow> {
|
|
761
761
|
}
|
762
762
|
}
|
763
763
|
|
764
|
+
impl TryConvert for Wrap<RoundMode> {
|
765
|
+
fn try_convert(ob: Value) -> RbResult<Self> {
|
766
|
+
let parsed = match String::try_convert(ob)?.as_str() {
|
767
|
+
"half_to_even" => RoundMode::HalfToEven,
|
768
|
+
"half_away_from_zero" => RoundMode::HalfAwayFromZero,
|
769
|
+
v => {
|
770
|
+
return Err(RbValueError::new_err(format!(
|
771
|
+
"`mode` must be one of {{'half_to_even', 'half_away_from_zero'}}, got {v}",
|
772
|
+
)));
|
773
|
+
}
|
774
|
+
};
|
775
|
+
Ok(Wrap(parsed))
|
776
|
+
}
|
777
|
+
}
|
778
|
+
|
764
779
|
impl TryConvert for Wrap<CsvEncoding> {
|
765
780
|
fn try_convert(ob: Value) -> RbResult<Self> {
|
766
781
|
let parsed = match String::try_convert(ob)?.as_str() {
|
@@ -1065,6 +1080,24 @@ impl TryConvert for Wrap<JoinValidation> {
|
|
1065
1080
|
}
|
1066
1081
|
}
|
1067
1082
|
|
1083
|
+
impl TryConvert for Wrap<MaintainOrderJoin> {
|
1084
|
+
fn try_convert(ob: Value) -> RbResult<Self> {
|
1085
|
+
let parsed = match String::try_convert(ob)?.as_str() {
|
1086
|
+
"none" => MaintainOrderJoin::None,
|
1087
|
+
"left" => MaintainOrderJoin::Left,
|
1088
|
+
"right" => MaintainOrderJoin::Right,
|
1089
|
+
"left_right" => MaintainOrderJoin::LeftRight,
|
1090
|
+
"right_left" => MaintainOrderJoin::RightLeft,
|
1091
|
+
v => {
|
1092
|
+
return Err(RbValueError::new_err(format!(
|
1093
|
+
"`maintain_order` must be one of {{'none', 'left', 'right', 'left_right', 'right_left'}}, got {v}",
|
1094
|
+
)))
|
1095
|
+
},
|
1096
|
+
};
|
1097
|
+
Ok(Wrap(parsed))
|
1098
|
+
}
|
1099
|
+
}
|
1100
|
+
|
1068
1101
|
impl TryConvert for Wrap<QuoteStyle> {
|
1069
1102
|
fn try_convert(ob: Value) -> RbResult<Self> {
|
1070
1103
|
let parsed = match String::try_convert(ob)?.as_str() {
|
@@ -18,7 +18,7 @@ impl RbDataFrame {
|
|
18
18
|
.get_columns()
|
19
19
|
.iter()
|
20
20
|
.map(|s| match s.dtype() {
|
21
|
-
DataType::Object(_
|
21
|
+
DataType::Object(_) => {
|
22
22
|
let obj: Option<&ObjectValue> = s.get_object(idx).map(|any| any.into());
|
23
23
|
obj.unwrap().to_value()
|
24
24
|
}
|
@@ -37,7 +37,7 @@ impl RbDataFrame {
|
|
37
37
|
.get_columns()
|
38
38
|
.iter()
|
39
39
|
.map(|s| match s.dtype() {
|
40
|
-
DataType::Object(_
|
40
|
+
DataType::Object(_) => {
|
41
41
|
let obj: Option<&ObjectValue> = s.get_object(idx).map(|any| any.into());
|
42
42
|
obj.unwrap().to_value()
|
43
43
|
}
|
@@ -1,3 +1,5 @@
|
|
1
|
+
use std::hash::BuildHasher;
|
2
|
+
|
1
3
|
use either::Either;
|
2
4
|
use magnus::{prelude::*, typed_data::Obj, IntoValue, RArray, Value};
|
3
5
|
use polars::prelude::pivot::{pivot, pivot_stable};
|
@@ -295,11 +297,11 @@ impl RbDataFrame {
|
|
295
297
|
Ok(())
|
296
298
|
}
|
297
299
|
|
298
|
-
pub fn slice(&self, offset:
|
299
|
-
let df = self
|
300
|
-
|
301
|
-
|
302
|
-
|
300
|
+
pub fn slice(&self, offset: i64, length: Option<usize>) -> Self {
|
301
|
+
let df = self
|
302
|
+
.df
|
303
|
+
.borrow()
|
304
|
+
.slice(offset, length.unwrap_or_else(|| self.df.borrow().height()));
|
303
305
|
df.into()
|
304
306
|
}
|
305
307
|
|
@@ -494,7 +496,8 @@ impl RbDataFrame {
|
|
494
496
|
}
|
495
497
|
|
496
498
|
pub fn hash_rows(&self, k0: u64, k1: u64, k2: u64, k3: u64) -> RbResult<RbSeries> {
|
497
|
-
let
|
499
|
+
let seed = PlFixedStateQuality::default().hash_one((k0, k1, k2, k3));
|
500
|
+
let hb = PlSeedableRandomStateQuality::seed_from_u64(seed);
|
498
501
|
let hash = self
|
499
502
|
.df
|
500
503
|
.borrow_mut()
|
@@ -371,14 +371,6 @@ impl RbExpr {
|
|
371
371
|
.into())
|
372
372
|
}
|
373
373
|
|
374
|
-
pub fn backward_fill(&self, limit: FillNullLimit) -> Self {
|
375
|
-
self.inner.clone().backward_fill(limit).into()
|
376
|
-
}
|
377
|
-
|
378
|
-
pub fn forward_fill(&self, limit: FillNullLimit) -> Self {
|
379
|
-
self.inner.clone().forward_fill(limit).into()
|
380
|
-
}
|
381
|
-
|
382
374
|
pub fn shift(&self, n: &Self, fill_value: Option<&Self>) -> Self {
|
383
375
|
let expr = self.inner.clone();
|
384
376
|
let out = match fill_value {
|
@@ -497,8 +489,8 @@ impl RbExpr {
|
|
497
489
|
.into()
|
498
490
|
}
|
499
491
|
|
500
|
-
pub fn round(&self, decimals: u32) -> Self {
|
501
|
-
self.inner.clone().round(decimals).into()
|
492
|
+
pub fn round(&self, decimals: u32, mode: Wrap<RoundMode>) -> Self {
|
493
|
+
self.inner.clone().round(decimals, mode.0).into()
|
502
494
|
}
|
503
495
|
|
504
496
|
pub fn floor(&self) -> Self {
|
@@ -597,8 +589,11 @@ impl RbExpr {
|
|
597
589
|
self.inner.clone().or(expr.inner.clone()).into()
|
598
590
|
}
|
599
591
|
|
600
|
-
pub fn is_in(&self, expr: &Self) -> Self {
|
601
|
-
self.inner
|
592
|
+
pub fn is_in(&self, expr: &Self, nulls_equal: bool) -> Self {
|
593
|
+
self.inner
|
594
|
+
.clone()
|
595
|
+
.is_in(expr.inner.clone(), nulls_equal)
|
596
|
+
.into()
|
602
597
|
}
|
603
598
|
|
604
599
|
pub fn repeat_by(&self, by: &Self) -> Self {
|
@@ -671,6 +666,10 @@ impl RbExpr {
|
|
671
666
|
self.inner.clone().interpolate(method.0).into()
|
672
667
|
}
|
673
668
|
|
669
|
+
pub fn interpolate_by(&self, by: &Self) -> Self {
|
670
|
+
self.inner.clone().interpolate_by(by.inner.clone()).into()
|
671
|
+
}
|
672
|
+
|
674
673
|
pub fn lower_bound(&self) -> Self {
|
675
674
|
self.inner.clone().lower_bound().into()
|
676
675
|
}
|
@@ -694,8 +693,11 @@ impl RbExpr {
|
|
694
693
|
self.inner.clone().rank(options, seed).into()
|
695
694
|
}
|
696
695
|
|
697
|
-
pub fn diff(&self, n:
|
698
|
-
self.inner
|
696
|
+
pub fn diff(&self, n: &Self, null_behavior: Wrap<NullBehavior>) -> Self {
|
697
|
+
self.inner
|
698
|
+
.clone()
|
699
|
+
.diff(n.inner.clone(), null_behavior.0)
|
700
|
+
.into()
|
699
701
|
}
|
700
702
|
|
701
703
|
pub fn pct_change(&self, n: &Self) -> Self {
|
@@ -319,7 +319,22 @@ impl RbExpr {
|
|
319
319
|
.into()
|
320
320
|
}
|
321
321
|
|
322
|
-
pub fn rolling_skew(
|
323
|
-
self
|
322
|
+
pub fn rolling_skew(
|
323
|
+
&self,
|
324
|
+
window_size: usize,
|
325
|
+
bias: bool,
|
326
|
+
min_periods: Option<usize>,
|
327
|
+
center: bool,
|
328
|
+
) -> Self {
|
329
|
+
let min_periods = min_periods.unwrap_or(window_size);
|
330
|
+
let options = RollingOptionsFixedWindow {
|
331
|
+
window_size,
|
332
|
+
weights: None,
|
333
|
+
min_periods,
|
334
|
+
center,
|
335
|
+
fn_params: Some(RollingFnParams::Skew { bias }),
|
336
|
+
};
|
337
|
+
|
338
|
+
self.inner.clone().rolling_skew(options).into()
|
324
339
|
}
|
325
340
|
}
|
data/ext/polars/src/file.rs
CHANGED
@@ -3,9 +3,12 @@ use std::io;
|
|
3
3
|
use std::io::{Cursor, Read, Seek, SeekFrom, Write};
|
4
4
|
use std::path::PathBuf;
|
5
5
|
|
6
|
-
use magnus::{exception, prelude::*, Error, RString, Value};
|
6
|
+
use magnus::{exception, prelude::*, value::Opaque, Error, RString, Ruby, Value};
|
7
7
|
use polars::io::cloud::CloudOptions;
|
8
8
|
use polars::io::mmap::MmapBytesReader;
|
9
|
+
use polars::prelude::file::DynWriteable;
|
10
|
+
use polars::prelude::sync_on_close::SyncOnCloseType;
|
11
|
+
use polars_utils::file::ClosableFile;
|
9
12
|
use polars_utils::mmap::MemSlice;
|
10
13
|
|
11
14
|
use crate::error::RbPolarsErr;
|
@@ -14,7 +17,22 @@ use crate::RbResult;
|
|
14
17
|
|
15
18
|
#[derive(Clone)]
|
16
19
|
pub struct RbFileLikeObject {
|
17
|
-
inner: Value
|
20
|
+
inner: Opaque<Value>,
|
21
|
+
}
|
22
|
+
|
23
|
+
impl DynWriteable for RbFileLikeObject {
|
24
|
+
fn as_dyn_write(&self) -> &(dyn io::Write + Send + 'static) {
|
25
|
+
self as _
|
26
|
+
}
|
27
|
+
fn as_mut_dyn_write(&mut self) -> &mut (dyn io::Write + Send + 'static) {
|
28
|
+
self as _
|
29
|
+
}
|
30
|
+
fn close(self: Box<Self>) -> io::Result<()> {
|
31
|
+
Ok(())
|
32
|
+
}
|
33
|
+
fn sync_on_close(&mut self, _sync_on_close: SyncOnCloseType) -> io::Result<()> {
|
34
|
+
Ok(())
|
35
|
+
}
|
18
36
|
}
|
19
37
|
|
20
38
|
/// Wraps a `Value`, and implements read, seek, and write for it.
|
@@ -23,7 +41,9 @@ impl RbFileLikeObject {
|
|
23
41
|
/// To assert the object has the required methods methods,
|
24
42
|
/// instantiate it with `RbFileLikeObject::require`
|
25
43
|
pub fn new(object: Value) -> Self {
|
26
|
-
RbFileLikeObject {
|
44
|
+
RbFileLikeObject {
|
45
|
+
inner: object.into(),
|
46
|
+
}
|
27
47
|
}
|
28
48
|
|
29
49
|
pub fn as_bytes(&self) -> bytes::Bytes {
|
@@ -31,8 +51,9 @@ impl RbFileLikeObject {
|
|
31
51
|
}
|
32
52
|
|
33
53
|
pub fn as_file_buffer(&self) -> Cursor<Vec<u8>> {
|
34
|
-
let bytes =
|
35
|
-
.
|
54
|
+
let bytes = Ruby::get()
|
55
|
+
.unwrap()
|
56
|
+
.get_inner(self.inner)
|
36
57
|
.funcall::<_, _, RString>("read", ())
|
37
58
|
.expect("no read method found");
|
38
59
|
|
@@ -77,8 +98,9 @@ fn rberr_to_io_err(e: Error) -> io::Error {
|
|
77
98
|
|
78
99
|
impl Read for RbFileLikeObject {
|
79
100
|
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, io::Error> {
|
80
|
-
let bytes =
|
81
|
-
.
|
101
|
+
let bytes = Ruby::get()
|
102
|
+
.unwrap()
|
103
|
+
.get_inner(self.inner)
|
82
104
|
.funcall::<_, _, RString>("read", (buf.len(),))
|
83
105
|
.map_err(rberr_to_io_err)?;
|
84
106
|
|
@@ -92,8 +114,9 @@ impl Write for RbFileLikeObject {
|
|
92
114
|
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
|
93
115
|
let rbbytes = RString::from_slice(buf);
|
94
116
|
|
95
|
-
let number_bytes_written =
|
96
|
-
.
|
117
|
+
let number_bytes_written = Ruby::get()
|
118
|
+
.unwrap()
|
119
|
+
.get_inner(self.inner)
|
97
120
|
.funcall::<_, _, usize>("write", (rbbytes,))
|
98
121
|
.map_err(rberr_to_io_err)?;
|
99
122
|
|
@@ -101,7 +124,9 @@ impl Write for RbFileLikeObject {
|
|
101
124
|
}
|
102
125
|
|
103
126
|
fn flush(&mut self) -> Result<(), io::Error> {
|
104
|
-
|
127
|
+
Ruby::get()
|
128
|
+
.unwrap()
|
129
|
+
.get_inner(self.inner)
|
105
130
|
.funcall::<_, _, Value>("flush", ())
|
106
131
|
.map_err(rberr_to_io_err)?;
|
107
132
|
|
@@ -117,8 +142,9 @@ impl Seek for RbFileLikeObject {
|
|
117
142
|
SeekFrom::End(i) => (2, i),
|
118
143
|
};
|
119
144
|
|
120
|
-
let new_position =
|
121
|
-
.
|
145
|
+
let new_position = Ruby::get()
|
146
|
+
.unwrap()
|
147
|
+
.get_inner(self.inner)
|
122
148
|
.funcall("seek", (offset, whence))
|
123
149
|
.map_err(rberr_to_io_err)?;
|
124
150
|
|
@@ -129,11 +155,12 @@ impl Seek for RbFileLikeObject {
|
|
129
155
|
pub trait FileLike: Read + Write + Seek {}
|
130
156
|
|
131
157
|
impl FileLike for File {}
|
158
|
+
impl FileLike for ClosableFile {}
|
132
159
|
impl FileLike for RbFileLikeObject {}
|
133
160
|
|
134
161
|
pub enum EitherRustRubyFile {
|
135
162
|
Rb(RbFileLikeObject),
|
136
|
-
Rust(
|
163
|
+
Rust(ClosableFile),
|
137
164
|
}
|
138
165
|
|
139
166
|
impl EitherRustRubyFile {
|
@@ -144,6 +171,13 @@ impl EitherRustRubyFile {
|
|
144
171
|
}
|
145
172
|
}
|
146
173
|
|
174
|
+
pub(crate) fn into_writeable(self) -> Box<dyn DynWriteable> {
|
175
|
+
match self {
|
176
|
+
Self::Rb(f) => Box::new(f),
|
177
|
+
Self::Rust(f) => Box::new(f),
|
178
|
+
}
|
179
|
+
}
|
180
|
+
|
147
181
|
pub fn into_dyn_writeable(self) -> Box<dyn Write> {
|
148
182
|
match self {
|
149
183
|
EitherRustRubyFile::Rb(f) => Box::new(f),
|
@@ -159,6 +193,14 @@ pub enum RubyScanSourceInput {
|
|
159
193
|
File(File),
|
160
194
|
}
|
161
195
|
|
196
|
+
pub(crate) fn try_get_rbfile(
|
197
|
+
rb_f: Value,
|
198
|
+
write: bool,
|
199
|
+
) -> RbResult<(EitherRustRubyFile, Option<PathBuf>)> {
|
200
|
+
let f = RbFileLikeObject::with_requirements(rb_f, !write, write, !write)?;
|
201
|
+
Ok((EitherRustRubyFile::Rb(f), None))
|
202
|
+
}
|
203
|
+
|
162
204
|
pub fn get_ruby_scan_source_input(rb_f: Value, write: bool) -> RbResult<RubyScanSourceInput> {
|
163
205
|
if let Ok(file_path) = PathBuf::try_convert(rb_f) {
|
164
206
|
// TODO resolve_homedir
|
@@ -184,7 +226,7 @@ pub fn get_either_file(rb_f: Value, truncate: bool) -> RbResult<EitherRustRubyFi
|
|
184
226
|
} else {
|
185
227
|
polars_utils::open_file(&file_path).map_err(RbPolarsErr::from)?
|
186
228
|
};
|
187
|
-
Ok(EitherRustRubyFile::Rust(f))
|
229
|
+
Ok(EitherRustRubyFile::Rust(f.into()))
|
188
230
|
} else {
|
189
231
|
let f = RbFileLikeObject::with_requirements(rb_f, !truncate, truncate, !truncate)?;
|
190
232
|
Ok(EitherRustRubyFile::Rb(f))
|
@@ -205,6 +205,21 @@ pub fn concat_lf_diagonal(
|
|
205
205
|
Ok(lf.into())
|
206
206
|
}
|
207
207
|
|
208
|
+
pub fn concat_lf_horizontal(lfs: RArray, parallel: bool) -> RbResult<RbLazyFrame> {
|
209
|
+
let iter = lfs.into_iter();
|
210
|
+
|
211
|
+
let lfs = iter.map(get_lf).collect::<RbResult<Vec<_>>>()?;
|
212
|
+
|
213
|
+
let args = UnionArgs {
|
214
|
+
rechunk: false, // No need to rechunk with horizontal concatenation
|
215
|
+
parallel,
|
216
|
+
to_supertypes: false,
|
217
|
+
..Default::default()
|
218
|
+
};
|
219
|
+
let lf = dsl::functions::concat_lf_horizontal(lfs, args).map_err(RbPolarsErr::from)?;
|
220
|
+
Ok(lf.into())
|
221
|
+
}
|
222
|
+
|
208
223
|
pub fn dtype_cols(dtypes: RArray) -> RbResult<RbExpr> {
|
209
224
|
let dtypes = dtypes
|
210
225
|
.into_iter()
|
@@ -263,7 +278,13 @@ pub fn first() -> RbExpr {
|
|
263
278
|
dsl::first().into()
|
264
279
|
}
|
265
280
|
|
266
|
-
pub fn fold(
|
281
|
+
pub fn fold(
|
282
|
+
acc: &RbExpr,
|
283
|
+
lambda: Value,
|
284
|
+
exprs: RArray,
|
285
|
+
returns_scalar: bool,
|
286
|
+
return_dtype: Option<Wrap<DataType>>,
|
287
|
+
) -> RbResult<RbExpr> {
|
267
288
|
let exprs = rb_exprs_to_exprs(exprs)?;
|
268
289
|
let lambda = Opaque::from(lambda);
|
269
290
|
|
@@ -275,7 +296,14 @@ pub fn fold(acc: &RbExpr, lambda: Value, exprs: RArray) -> RbResult<RbExpr> {
|
|
275
296
|
)
|
276
297
|
.map(|v| v.map(Column::from))
|
277
298
|
};
|
278
|
-
Ok(dsl::fold_exprs(
|
299
|
+
Ok(dsl::fold_exprs(
|
300
|
+
acc.inner.clone(),
|
301
|
+
func,
|
302
|
+
exprs,
|
303
|
+
returns_scalar,
|
304
|
+
return_dtype.map(|w| w.0),
|
305
|
+
)
|
306
|
+
.into())
|
279
307
|
}
|
280
308
|
|
281
309
|
pub fn last() -> RbExpr {
|
@@ -0,0 +1,52 @@
|
|
1
|
+
use magnus::{class, prelude::*, IntoValue, Module, RArray, RClass, RModule, Value};
|
2
|
+
|
3
|
+
use crate::RbResult;
|
4
|
+
|
5
|
+
pub trait Element: IntoValue {
|
6
|
+
fn class_name() -> &'static str;
|
7
|
+
}
|
8
|
+
|
9
|
+
macro_rules! create_element {
|
10
|
+
($type:ty, $name:expr) => {
|
11
|
+
impl Element for $type {
|
12
|
+
fn class_name() -> &'static str {
|
13
|
+
$name
|
14
|
+
}
|
15
|
+
}
|
16
|
+
};
|
17
|
+
}
|
18
|
+
|
19
|
+
create_element!(i8, "Int8");
|
20
|
+
create_element!(i16, "Int16");
|
21
|
+
create_element!(i32, "Int32");
|
22
|
+
create_element!(i64, "Int64");
|
23
|
+
create_element!(u8, "UInt8");
|
24
|
+
create_element!(u16, "UInt16");
|
25
|
+
create_element!(u32, "UInt32");
|
26
|
+
create_element!(u64, "UInt64");
|
27
|
+
create_element!(f32, "SFloat");
|
28
|
+
create_element!(f64, "DFloat");
|
29
|
+
create_element!(bool, "Bit");
|
30
|
+
|
31
|
+
impl<T> Element for Option<T>
|
32
|
+
where
|
33
|
+
Option<T>: IntoValue,
|
34
|
+
{
|
35
|
+
fn class_name() -> &'static str {
|
36
|
+
"RObject"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
pub struct RbArray1<T>(T);
|
41
|
+
|
42
|
+
impl<T: Element> RbArray1<T> {
|
43
|
+
pub fn from_iter<I>(values: I) -> RbResult<Value>
|
44
|
+
where
|
45
|
+
I: IntoIterator<Item = T>,
|
46
|
+
{
|
47
|
+
class::object()
|
48
|
+
.const_get::<_, RModule>("Numo")?
|
49
|
+
.const_get::<_, RClass>(T::class_name())?
|
50
|
+
.funcall("cast", (RArray::from_iter(values),))
|
51
|
+
}
|
52
|
+
}
|