polars-df 0.17.1 → 0.19.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 +8 -0
- data/Cargo.lock +725 -453
- data/ext/polars/Cargo.toml +8 -8
- data/ext/polars/src/conversion/any_value.rs +1 -1
- data/ext/polars/src/conversion/mod.rs +38 -7
- data/ext/polars/src/dataframe/export.rs +2 -2
- data/ext/polars/src/dataframe/general.rs +4 -1
- data/ext/polars/src/expr/array.rs +2 -2
- data/ext/polars/src/expr/datetime.rs +16 -9
- data/ext/polars/src/expr/general.rs +12 -14
- data/ext/polars/src/expr/list.rs +3 -3
- data/ext/polars/src/expr/rolling.rs +17 -2
- data/ext/polars/src/expr/string.rs +2 -2
- data/ext/polars/src/file.rs +56 -14
- data/ext/polars/src/functions/lazy.rs +26 -4
- data/ext/polars/src/functions/range.rs +4 -4
- data/ext/polars/src/lazyframe/general.rs +87 -48
- data/ext/polars/src/lazyframe/mod.rs +2 -0
- data/ext/polars/src/lazyframe/sink.rs +99 -0
- data/ext/polars/src/lib.rs +7 -9
- 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/array_expr.rb +4 -2
- data/lib/polars/expr.rb +28 -28
- data/lib/polars/functions/lit.rb +4 -9
- data/lib/polars/io/database.rb +2 -2
- data/lib/polars/lazy_frame.rb +78 -14
- data/lib/polars/list_expr.rb +10 -11
- data/lib/polars/series.rb +29 -12
- data/lib/polars/string_expr.rb +3 -3
- data/lib/polars/version.rb +1 -1
- metadata +4 -3
data/ext/polars/Cargo.toml
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
[package]
|
2
2
|
name = "polars"
|
3
|
-
version = "0.
|
3
|
+
version = "0.19.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,22 +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.48.0" }
|
16
16
|
bytes = "1"
|
17
17
|
chrono = "0.4"
|
18
18
|
either = "1.8"
|
19
19
|
magnus = "0.7"
|
20
20
|
num-traits = "0.2"
|
21
|
-
polars-core = "=0.
|
22
|
-
polars-plan = "=0.
|
23
|
-
polars-parquet = "=0.
|
24
|
-
polars-utils = "=0.
|
21
|
+
polars-core = "=0.48.0"
|
22
|
+
polars-plan = "=0.48.0"
|
23
|
+
polars-parquet = "=0.48.0"
|
24
|
+
polars-utils = "=0.48.0"
|
25
25
|
rayon = "1.9"
|
26
26
|
regex = "1"
|
27
27
|
serde_json = "1"
|
28
28
|
|
29
29
|
[dependencies.polars]
|
30
|
-
version = "=0.
|
30
|
+
version = "=0.48.0"
|
31
31
|
features = [
|
32
32
|
"abs",
|
33
33
|
"approx_unique",
|
@@ -173,7 +173,7 @@ pub(crate) fn rb_object_to_any_value<'s>(ob: Value, strict: bool) -> RbResult<An
|
|
173
173
|
}
|
174
174
|
|
175
175
|
fn get_struct(ob: Value, _strict: bool) -> RbResult<AnyValue<'static>> {
|
176
|
-
let dict = RHash::
|
176
|
+
let dict = RHash::try_convert(ob)?;
|
177
177
|
let len = dict.len();
|
178
178
|
let mut keys = Vec::with_capacity(len);
|
179
179
|
let mut vals = Vec::with_capacity(len);
|
@@ -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
|
|
@@ -210,7 +210,10 @@ impl IntoValue for Wrap<DataType> {
|
|
210
210
|
DataType::Datetime(tu, tz) => {
|
211
211
|
let datetime_class = pl.const_get::<_, Value>("Datetime").unwrap();
|
212
212
|
datetime_class
|
213
|
-
.funcall::<_, _, Value>(
|
213
|
+
.funcall::<_, _, Value>(
|
214
|
+
"new",
|
215
|
+
(tu.to_ascii(), tz.as_deref().map(|x| x.as_str())),
|
216
|
+
)
|
214
217
|
.unwrap()
|
215
218
|
}
|
216
219
|
DataType::Duration(tu) => {
|
@@ -219,7 +222,7 @@ impl IntoValue for Wrap<DataType> {
|
|
219
222
|
.funcall::<_, _, Value>("new", (tu.to_ascii(),))
|
220
223
|
.unwrap()
|
221
224
|
}
|
222
|
-
DataType::Object(_
|
225
|
+
DataType::Object(_) => {
|
223
226
|
let class = pl.const_get::<_, Value>("Object").unwrap();
|
224
227
|
class.funcall("new", ()).unwrap()
|
225
228
|
}
|
@@ -332,7 +335,7 @@ impl TryConvert for Wrap<DataType> {
|
|
332
335
|
"Polars::Array" => DataType::Array(Box::new(DataType::Null), 0),
|
333
336
|
"Polars::Struct" => DataType::Struct(vec![]),
|
334
337
|
"Polars::Null" => DataType::Null,
|
335
|
-
"Polars::Object" => DataType::Object(OBJECT_NAME
|
338
|
+
"Polars::Object" => DataType::Object(OBJECT_NAME),
|
336
339
|
"Polars::Unknown" => DataType::Unknown(Default::default()),
|
337
340
|
dt => {
|
338
341
|
return Err(RbValueError::new_err(format!(
|
@@ -375,7 +378,10 @@ impl TryConvert for Wrap<DataType> {
|
|
375
378
|
let time_unit: Value = ob.funcall("time_unit", ()).unwrap();
|
376
379
|
let time_unit = Wrap::<TimeUnit>::try_convert(time_unit)?.0;
|
377
380
|
let time_zone: Option<String> = ob.funcall("time_zone", ())?;
|
378
|
-
DataType::Datetime(
|
381
|
+
DataType::Datetime(
|
382
|
+
time_unit,
|
383
|
+
TimeZone::opt_try_new(time_zone.as_deref()).map_err(RbPolarsErr::from)?,
|
384
|
+
)
|
379
385
|
}
|
380
386
|
"Polars::Duration" => {
|
381
387
|
let time_unit: Value = ob.funcall("time_unit", ()).unwrap();
|
@@ -408,7 +414,7 @@ impl TryConvert for Wrap<DataType> {
|
|
408
414
|
DataType::Struct(fields)
|
409
415
|
}
|
410
416
|
"Polars::Null" => DataType::Null,
|
411
|
-
"Object" => DataType::Object(OBJECT_NAME
|
417
|
+
"Object" => DataType::Object(OBJECT_NAME),
|
412
418
|
"Polars::Unknown" => DataType::Unknown(Default::default()),
|
413
419
|
dt => {
|
414
420
|
return Err(RbTypeError::new_err(format!(
|
@@ -437,7 +443,7 @@ impl TryConvert for Wrap<DataType> {
|
|
437
443
|
"time" => DataType::Time,
|
438
444
|
"dur" => DataType::Duration(TimeUnit::Microseconds),
|
439
445
|
"f64" => DataType::Float64,
|
440
|
-
"obj" => DataType::Object(OBJECT_NAME
|
446
|
+
"obj" => DataType::Object(OBJECT_NAME),
|
441
447
|
"list" => DataType::List(Box::new(DataType::Boolean)),
|
442
448
|
"null" => DataType::Null,
|
443
449
|
"unk" => DataType::Unknown(Default::default()),
|
@@ -761,6 +767,21 @@ impl TryConvert for Wrap<ClosedWindow> {
|
|
761
767
|
}
|
762
768
|
}
|
763
769
|
|
770
|
+
impl TryConvert for Wrap<RoundMode> {
|
771
|
+
fn try_convert(ob: Value) -> RbResult<Self> {
|
772
|
+
let parsed = match String::try_convert(ob)?.as_str() {
|
773
|
+
"half_to_even" => RoundMode::HalfToEven,
|
774
|
+
"half_away_from_zero" => RoundMode::HalfAwayFromZero,
|
775
|
+
v => {
|
776
|
+
return Err(RbValueError::new_err(format!(
|
777
|
+
"`mode` must be one of {{'half_to_even', 'half_away_from_zero'}}, got {v}",
|
778
|
+
)));
|
779
|
+
}
|
780
|
+
};
|
781
|
+
Ok(Wrap(parsed))
|
782
|
+
}
|
783
|
+
}
|
784
|
+
|
764
785
|
impl TryConvert for Wrap<CsvEncoding> {
|
765
786
|
fn try_convert(ob: Value) -> RbResult<Self> {
|
766
787
|
let parsed = match String::try_convert(ob)?.as_str() {
|
@@ -1214,3 +1235,13 @@ impl TryConvert for RbCompatLevel {
|
|
1214
1235
|
}))
|
1215
1236
|
}
|
1216
1237
|
}
|
1238
|
+
|
1239
|
+
impl TryConvert for Wrap<Option<TimeZone>> {
|
1240
|
+
fn try_convert(ob: Value) -> RbResult<Self> {
|
1241
|
+
let tz = Option::<Wrap<PlSmallStr>>::try_convert(ob)?;
|
1242
|
+
|
1243
|
+
let tz = tz.map(|x| x.0);
|
1244
|
+
|
1245
|
+
Ok(Wrap(TimeZone::opt_try_new(tz).map_err(RbPolarsErr::from)?))
|
1246
|
+
}
|
1247
|
+
}
|
@@ -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};
|
@@ -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()
|
@@ -75,11 +75,11 @@ impl RbExpr {
|
|
75
75
|
.into()
|
76
76
|
}
|
77
77
|
|
78
|
-
pub fn arr_contains(&self, other: &RbExpr) -> Self {
|
78
|
+
pub fn arr_contains(&self, other: &RbExpr, nulls_equal: bool) -> Self {
|
79
79
|
self.inner
|
80
80
|
.clone()
|
81
81
|
.arr()
|
82
|
-
.contains(other.inner.clone())
|
82
|
+
.contains(other.inner.clone(), nulls_equal)
|
83
83
|
.into()
|
84
84
|
}
|
85
85
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
use polars::prelude::*;
|
2
2
|
|
3
3
|
use crate::conversion::Wrap;
|
4
|
-
use crate::RbExpr;
|
4
|
+
use crate::{RbExpr, RbPolarsErr, RbResult};
|
5
5
|
|
6
6
|
impl RbExpr {
|
7
7
|
pub fn dt_to_string(&self, format: String) -> Self {
|
@@ -30,12 +30,17 @@ impl RbExpr {
|
|
30
30
|
self.inner.clone().dt().with_time_unit(tu.0).into()
|
31
31
|
}
|
32
32
|
|
33
|
-
pub fn dt_convert_time_zone(&self, time_zone: String) -> Self {
|
34
|
-
self
|
33
|
+
pub fn dt_convert_time_zone(&self, time_zone: String) -> RbResult<Self> {
|
34
|
+
Ok(self
|
35
|
+
.inner
|
35
36
|
.clone()
|
36
37
|
.dt()
|
37
|
-
.convert_time_zone(
|
38
|
-
|
38
|
+
.convert_time_zone(
|
39
|
+
TimeZone::opt_try_new(Some(PlSmallStr::from(time_zone)))
|
40
|
+
.map_err(RbPolarsErr::from)?
|
41
|
+
.unwrap_or(TimeZone::UTC),
|
42
|
+
)
|
43
|
+
.into())
|
39
44
|
}
|
40
45
|
|
41
46
|
pub fn dt_cast_time_unit(&self, tu: Wrap<TimeUnit>) -> Self {
|
@@ -47,16 +52,18 @@ impl RbExpr {
|
|
47
52
|
time_zone: Option<String>,
|
48
53
|
ambiguous: &Self,
|
49
54
|
non_existent: Wrap<NonExistent>,
|
50
|
-
) -> Self {
|
51
|
-
self
|
55
|
+
) -> RbResult<Self> {
|
56
|
+
Ok(self
|
57
|
+
.inner
|
52
58
|
.clone()
|
53
59
|
.dt()
|
54
60
|
.replace_time_zone(
|
55
|
-
time_zone.map(
|
61
|
+
TimeZone::opt_try_new(time_zone.map(PlSmallStr::from_string))
|
62
|
+
.map_err(RbPolarsErr::from)?,
|
56
63
|
ambiguous.inner.clone(),
|
57
64
|
non_existent.0,
|
58
65
|
)
|
59
|
-
.into()
|
66
|
+
.into())
|
60
67
|
}
|
61
68
|
|
62
69
|
pub fn dt_truncate(&self, every: &Self) -> Self {
|
@@ -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 {
|
@@ -698,8 +693,11 @@ impl RbExpr {
|
|
698
693
|
self.inner.clone().rank(options, seed).into()
|
699
694
|
}
|
700
695
|
|
701
|
-
pub fn diff(&self, n:
|
702
|
-
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()
|
703
701
|
}
|
704
702
|
|
705
703
|
pub fn pct_change(&self, n: &Self) -> Self {
|
data/ext/polars/src/expr/list.rs
CHANGED
@@ -23,11 +23,11 @@ impl RbExpr {
|
|
23
23
|
self.inner.clone().list().arg_min().into()
|
24
24
|
}
|
25
25
|
|
26
|
-
pub fn list_contains(&self, other: &RbExpr) -> Self {
|
26
|
+
pub fn list_contains(&self, other: &RbExpr, nulls_equal: bool) -> Self {
|
27
27
|
self.inner
|
28
28
|
.clone()
|
29
29
|
.list()
|
30
|
-
.contains(other.inner.clone())
|
30
|
+
.contains(other.inner.clone(), nulls_equal)
|
31
31
|
.into()
|
32
32
|
}
|
33
33
|
|
@@ -180,7 +180,7 @@ impl RbExpr {
|
|
180
180
|
&self,
|
181
181
|
width_strat: Wrap<ListToStructWidthStrategy>,
|
182
182
|
name_gen: Option<Value>,
|
183
|
-
upper_bound: usize
|
183
|
+
upper_bound: Option<usize>,
|
184
184
|
) -> RbResult<Self> {
|
185
185
|
let name_gen = name_gen.map(|lambda| {
|
186
186
|
let lambda = Opaque::from(lambda);
|
@@ -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
|
}
|
@@ -35,14 +35,14 @@ impl RbExpr {
|
|
35
35
|
&self,
|
36
36
|
format: Option<String>,
|
37
37
|
time_unit: Option<Wrap<TimeUnit>>,
|
38
|
-
time_zone: Option<
|
38
|
+
time_zone: Wrap<Option<TimeZone>>,
|
39
39
|
strict: bool,
|
40
40
|
exact: bool,
|
41
41
|
cache: bool,
|
42
42
|
ambiguous: &Self,
|
43
43
|
) -> Self {
|
44
44
|
let format = format.map(|x| x.into());
|
45
|
-
let time_zone = time_zone.
|
45
|
+
let time_zone = time_zone.0;
|
46
46
|
|
47
47
|
let options = StrptimeOptions {
|
48
48
|
format,
|
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))
|
@@ -278,7 +278,13 @@ pub fn first() -> RbExpr {
|
|
278
278
|
dsl::first().into()
|
279
279
|
}
|
280
280
|
|
281
|
-
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> {
|
282
288
|
let exprs = rb_exprs_to_exprs(exprs)?;
|
283
289
|
let lambda = Opaque::from(lambda);
|
284
290
|
|
@@ -290,14 +296,21 @@ pub fn fold(acc: &RbExpr, lambda: Value, exprs: RArray) -> RbResult<RbExpr> {
|
|
290
296
|
)
|
291
297
|
.map(|v| v.map(Column::from))
|
292
298
|
};
|
293
|
-
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())
|
294
307
|
}
|
295
308
|
|
296
309
|
pub fn last() -> RbExpr {
|
297
310
|
dsl::last().into()
|
298
311
|
}
|
299
312
|
|
300
|
-
pub fn lit(value: Value, allow_object: bool) -> RbResult<RbExpr> {
|
313
|
+
pub fn lit(value: Value, allow_object: bool, is_scalar: bool) -> RbResult<RbExpr> {
|
301
314
|
if value.is_kind_of(class::true_class()) || value.is_kind_of(class::false_class()) {
|
302
315
|
Ok(dsl::lit(bool::try_convert(value)?).into())
|
303
316
|
} else if let Some(v) = Integer::from_value(value) {
|
@@ -323,7 +336,16 @@ pub fn lit(value: Value, allow_object: bool) -> RbResult<RbExpr> {
|
|
323
336
|
Ok(dsl::lit(unsafe { v.as_slice() }).into())
|
324
337
|
}
|
325
338
|
} else if let Ok(series) = Obj::<RbSeries>::try_convert(value) {
|
326
|
-
|
339
|
+
let s = series.series.borrow();
|
340
|
+
if is_scalar {
|
341
|
+
let av = s
|
342
|
+
.get(0)
|
343
|
+
.map_err(|_| RbValueError::new_err("expected at least 1 value"))?;
|
344
|
+
let av = av.into_static();
|
345
|
+
Ok(dsl::lit(Scalar::new(s.dtype().clone(), av)).into())
|
346
|
+
} else {
|
347
|
+
Ok(dsl::lit(s.clone()).into())
|
348
|
+
}
|
327
349
|
} else if value.is_nil() {
|
328
350
|
Ok(dsl::lit(Null {}).into())
|
329
351
|
} else if allow_object {
|
@@ -56,14 +56,14 @@ pub fn datetime_range(
|
|
56
56
|
every: String,
|
57
57
|
closed: Wrap<ClosedWindow>,
|
58
58
|
time_unit: Option<Wrap<TimeUnit>>,
|
59
|
-
time_zone: Option<
|
59
|
+
time_zone: Wrap<Option<TimeZone>>,
|
60
60
|
) -> RbExpr {
|
61
61
|
let start = start.inner.clone();
|
62
62
|
let end = end.inner.clone();
|
63
63
|
let every = Duration::parse(&every);
|
64
64
|
let closed = closed.0;
|
65
65
|
let time_unit = time_unit.map(|x| x.0);
|
66
|
-
let time_zone = time_zone.
|
66
|
+
let time_zone = time_zone.0;
|
67
67
|
dsl::datetime_range(start, end, every, closed, time_unit, time_zone).into()
|
68
68
|
}
|
69
69
|
|
@@ -73,14 +73,14 @@ pub fn datetime_ranges(
|
|
73
73
|
every: String,
|
74
74
|
closed: Wrap<ClosedWindow>,
|
75
75
|
time_unit: Option<Wrap<TimeUnit>>,
|
76
|
-
time_zone: Option<
|
76
|
+
time_zone: Wrap<Option<TimeZone>>,
|
77
77
|
) -> RbExpr {
|
78
78
|
let start = start.inner.clone();
|
79
79
|
let end = end.inner.clone();
|
80
80
|
let every = Duration::parse(&every);
|
81
81
|
let closed = closed.0;
|
82
82
|
let time_unit = time_unit.map(|x| x.0);
|
83
|
-
let time_zone = time_zone.
|
83
|
+
let time_zone = time_zone.0;
|
84
84
|
dsl::datetime_ranges(start, end, every, closed, time_unit, time_zone).into()
|
85
85
|
}
|
86
86
|
|