polars-df 0.9.0 → 0.11.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 +23 -0
- data/Cargo.lock +144 -57
- data/README.md +7 -6
- data/ext/polars/Cargo.toml +10 -6
- data/ext/polars/src/batched_csv.rs +53 -50
- data/ext/polars/src/conversion/anyvalue.rs +3 -2
- data/ext/polars/src/conversion/mod.rs +31 -67
- data/ext/polars/src/dataframe/construction.rs +186 -0
- data/ext/polars/src/dataframe/export.rs +48 -0
- data/ext/polars/src/dataframe/general.rs +607 -0
- data/ext/polars/src/dataframe/io.rs +463 -0
- data/ext/polars/src/dataframe/mod.rs +26 -0
- data/ext/polars/src/expr/array.rs +6 -2
- data/ext/polars/src/expr/datetime.rs +13 -4
- data/ext/polars/src/expr/general.rs +50 -9
- data/ext/polars/src/expr/list.rs +6 -2
- data/ext/polars/src/expr/rolling.rs +185 -69
- data/ext/polars/src/expr/string.rs +12 -33
- data/ext/polars/src/file.rs +158 -11
- data/ext/polars/src/functions/lazy.rs +20 -3
- data/ext/polars/src/functions/range.rs +74 -0
- data/ext/polars/src/functions/whenthen.rs +47 -17
- data/ext/polars/src/interop/mod.rs +1 -0
- data/ext/polars/src/interop/numo/mod.rs +2 -0
- data/ext/polars/src/interop/numo/to_numo_df.rs +23 -0
- data/ext/polars/src/interop/numo/to_numo_series.rs +60 -0
- data/ext/polars/src/lazyframe/mod.rs +111 -56
- data/ext/polars/src/lib.rs +68 -34
- data/ext/polars/src/map/dataframe.rs +17 -9
- data/ext/polars/src/map/lazy.rs +5 -25
- data/ext/polars/src/map/series.rs +7 -1
- data/ext/polars/src/series/aggregation.rs +47 -30
- data/ext/polars/src/series/export.rs +131 -49
- data/ext/polars/src/series/mod.rs +13 -133
- data/lib/polars/array_expr.rb +6 -2
- data/lib/polars/batched_csv_reader.rb +11 -3
- data/lib/polars/convert.rb +6 -1
- data/lib/polars/data_frame.rb +225 -370
- data/lib/polars/date_time_expr.rb +11 -4
- data/lib/polars/date_time_name_space.rb +14 -4
- data/lib/polars/dynamic_group_by.rb +2 -2
- data/lib/polars/exceptions.rb +4 -0
- data/lib/polars/expr.rb +1171 -54
- data/lib/polars/functions/lazy.rb +3 -3
- data/lib/polars/functions/range/date_range.rb +92 -0
- data/lib/polars/functions/range/datetime_range.rb +149 -0
- data/lib/polars/functions/range/time_range.rb +141 -0
- data/lib/polars/functions/whenthen.rb +74 -5
- data/lib/polars/group_by.rb +88 -23
- data/lib/polars/io/avro.rb +24 -0
- data/lib/polars/{io.rb → io/csv.rb} +307 -489
- data/lib/polars/io/database.rb +73 -0
- data/lib/polars/io/ipc.rb +247 -0
- data/lib/polars/io/json.rb +18 -0
- data/lib/polars/io/ndjson.rb +69 -0
- data/lib/polars/io/parquet.rb +226 -0
- data/lib/polars/lazy_frame.rb +55 -195
- data/lib/polars/lazy_group_by.rb +100 -3
- data/lib/polars/list_expr.rb +6 -2
- data/lib/polars/rolling_group_by.rb +2 -2
- data/lib/polars/series.rb +14 -12
- data/lib/polars/string_expr.rb +38 -36
- data/lib/polars/utils.rb +89 -1
- data/lib/polars/version.rb +1 -1
- data/lib/polars/whenthen.rb +83 -0
- data/lib/polars.rb +10 -3
- metadata +23 -8
- data/ext/polars/src/dataframe.rs +0 -1182
- data/lib/polars/when.rb +0 -16
- data/lib/polars/when_then.rb +0 -19
@@ -7,187 +7,281 @@ use crate::RbExpr;
|
|
7
7
|
impl RbExpr {
|
8
8
|
pub fn rolling_sum(
|
9
9
|
&self,
|
10
|
-
window_size:
|
10
|
+
window_size: usize,
|
11
11
|
weights: Option<Vec<f64>>,
|
12
12
|
min_periods: usize,
|
13
13
|
center: bool,
|
14
|
-
by: Option<String>,
|
15
|
-
closed: Option<Wrap<ClosedWindow>>,
|
16
14
|
) -> Self {
|
17
|
-
let options =
|
18
|
-
window_size
|
15
|
+
let options = RollingOptionsFixedWindow {
|
16
|
+
window_size,
|
19
17
|
weights,
|
20
18
|
min_periods,
|
21
19
|
center,
|
22
|
-
by,
|
23
|
-
closed_window: closed.map(|c| c.0),
|
24
20
|
..Default::default()
|
25
21
|
};
|
26
22
|
self.inner.clone().rolling_sum(options).into()
|
27
23
|
}
|
28
24
|
|
29
|
-
pub fn
|
25
|
+
pub fn rolling_sum_by(
|
30
26
|
&self,
|
27
|
+
by: &RbExpr,
|
31
28
|
window_size: String,
|
29
|
+
min_periods: usize,
|
30
|
+
closed: Wrap<ClosedWindow>,
|
31
|
+
) -> Self {
|
32
|
+
let options = RollingOptionsDynamicWindow {
|
33
|
+
window_size: Duration::parse(&window_size),
|
34
|
+
min_periods,
|
35
|
+
closed_window: closed.0,
|
36
|
+
fn_params: None,
|
37
|
+
};
|
38
|
+
self.inner
|
39
|
+
.clone()
|
40
|
+
.rolling_sum_by(by.inner.clone(), options)
|
41
|
+
.into()
|
42
|
+
}
|
43
|
+
|
44
|
+
pub fn rolling_min(
|
45
|
+
&self,
|
46
|
+
window_size: usize,
|
32
47
|
weights: Option<Vec<f64>>,
|
33
48
|
min_periods: usize,
|
34
49
|
center: bool,
|
35
|
-
by: Option<String>,
|
36
|
-
closed: Option<Wrap<ClosedWindow>>,
|
37
50
|
) -> Self {
|
38
|
-
let options =
|
39
|
-
window_size
|
51
|
+
let options = RollingOptionsFixedWindow {
|
52
|
+
window_size,
|
40
53
|
weights,
|
41
54
|
min_periods,
|
42
55
|
center,
|
43
|
-
by,
|
44
|
-
closed_window: closed.map(|c| c.0),
|
45
56
|
..Default::default()
|
46
57
|
};
|
47
58
|
self.inner.clone().rolling_min(options).into()
|
48
59
|
}
|
49
60
|
|
50
|
-
pub fn
|
61
|
+
pub fn rolling_min_by(
|
51
62
|
&self,
|
63
|
+
by: &RbExpr,
|
52
64
|
window_size: String,
|
65
|
+
min_periods: usize,
|
66
|
+
closed: Wrap<ClosedWindow>,
|
67
|
+
) -> Self {
|
68
|
+
let options = RollingOptionsDynamicWindow {
|
69
|
+
window_size: Duration::parse(&window_size),
|
70
|
+
min_periods,
|
71
|
+
closed_window: closed.0,
|
72
|
+
fn_params: None,
|
73
|
+
};
|
74
|
+
self.inner
|
75
|
+
.clone()
|
76
|
+
.rolling_min_by(by.inner.clone(), options)
|
77
|
+
.into()
|
78
|
+
}
|
79
|
+
|
80
|
+
pub fn rolling_max(
|
81
|
+
&self,
|
82
|
+
window_size: usize,
|
53
83
|
weights: Option<Vec<f64>>,
|
54
84
|
min_periods: usize,
|
55
85
|
center: bool,
|
56
|
-
by: Option<String>,
|
57
|
-
closed: Option<Wrap<ClosedWindow>>,
|
58
86
|
) -> Self {
|
59
|
-
let options =
|
60
|
-
window_size:
|
87
|
+
let options = RollingOptionsFixedWindow {
|
88
|
+
window_size: window_size,
|
61
89
|
weights,
|
62
90
|
min_periods,
|
63
91
|
center,
|
64
|
-
by,
|
65
|
-
closed_window: closed.map(|c| c.0),
|
66
92
|
..Default::default()
|
67
93
|
};
|
68
94
|
self.inner.clone().rolling_max(options).into()
|
69
95
|
}
|
70
96
|
|
71
|
-
pub fn
|
97
|
+
pub fn rolling_max_by(
|
72
98
|
&self,
|
99
|
+
by: &RbExpr,
|
73
100
|
window_size: String,
|
101
|
+
min_periods: usize,
|
102
|
+
closed: Wrap<ClosedWindow>,
|
103
|
+
) -> Self {
|
104
|
+
let options = RollingOptionsDynamicWindow {
|
105
|
+
window_size: Duration::parse(&window_size),
|
106
|
+
min_periods,
|
107
|
+
closed_window: closed.0,
|
108
|
+
fn_params: None,
|
109
|
+
};
|
110
|
+
self.inner
|
111
|
+
.clone()
|
112
|
+
.rolling_max_by(by.inner.clone(), options)
|
113
|
+
.into()
|
114
|
+
}
|
115
|
+
|
116
|
+
pub fn rolling_mean(
|
117
|
+
&self,
|
118
|
+
window_size: usize,
|
74
119
|
weights: Option<Vec<f64>>,
|
75
120
|
min_periods: usize,
|
76
121
|
center: bool,
|
77
|
-
by: Option<String>,
|
78
|
-
closed: Option<Wrap<ClosedWindow>>,
|
79
122
|
) -> Self {
|
80
|
-
let options =
|
81
|
-
window_size
|
123
|
+
let options = RollingOptionsFixedWindow {
|
124
|
+
window_size,
|
82
125
|
weights,
|
83
126
|
min_periods,
|
84
127
|
center,
|
85
|
-
by,
|
86
|
-
closed_window: closed.map(|c| c.0),
|
87
128
|
..Default::default()
|
88
129
|
};
|
89
130
|
|
90
131
|
self.inner.clone().rolling_mean(options).into()
|
91
132
|
}
|
92
133
|
|
93
|
-
|
94
|
-
pub fn rolling_std(
|
134
|
+
pub fn rolling_mean_by(
|
95
135
|
&self,
|
136
|
+
by: &RbExpr,
|
96
137
|
window_size: String,
|
138
|
+
min_periods: usize,
|
139
|
+
closed: Wrap<ClosedWindow>,
|
140
|
+
) -> Self {
|
141
|
+
let options = RollingOptionsDynamicWindow {
|
142
|
+
window_size: Duration::parse(&window_size),
|
143
|
+
min_periods,
|
144
|
+
closed_window: closed.0,
|
145
|
+
fn_params: None,
|
146
|
+
};
|
147
|
+
|
148
|
+
self.inner
|
149
|
+
.clone()
|
150
|
+
.rolling_mean_by(by.inner.clone(), options)
|
151
|
+
.into()
|
152
|
+
}
|
153
|
+
|
154
|
+
pub fn rolling_std(
|
155
|
+
&self,
|
156
|
+
window_size: usize,
|
97
157
|
weights: Option<Vec<f64>>,
|
98
158
|
min_periods: usize,
|
99
159
|
center: bool,
|
100
|
-
by: Option<String>,
|
101
|
-
closed: Option<Wrap<ClosedWindow>>,
|
102
160
|
ddof: u8,
|
103
|
-
warn_if_unsorted: bool,
|
104
161
|
) -> Self {
|
105
|
-
let options =
|
106
|
-
window_size
|
162
|
+
let options = RollingOptionsFixedWindow {
|
163
|
+
window_size,
|
107
164
|
weights,
|
108
165
|
min_periods,
|
109
166
|
center,
|
110
|
-
by,
|
111
|
-
closed_window: closed.map(|c| c.0),
|
112
167
|
fn_params: Some(Arc::new(RollingVarParams { ddof }) as Arc<dyn Any + Send + Sync>),
|
113
|
-
warn_if_unsorted,
|
114
168
|
};
|
115
169
|
|
116
170
|
self.inner.clone().rolling_std(options).into()
|
117
171
|
}
|
118
172
|
|
119
|
-
|
120
|
-
pub fn rolling_var(
|
173
|
+
pub fn rolling_std_by(
|
121
174
|
&self,
|
175
|
+
by: &RbExpr,
|
122
176
|
window_size: String,
|
177
|
+
min_periods: usize,
|
178
|
+
closed: Wrap<ClosedWindow>,
|
179
|
+
ddof: u8,
|
180
|
+
) -> Self {
|
181
|
+
let options = RollingOptionsDynamicWindow {
|
182
|
+
window_size: Duration::parse(&window_size),
|
183
|
+
min_periods,
|
184
|
+
closed_window: closed.0,
|
185
|
+
fn_params: Some(Arc::new(RollingVarParams { ddof }) as Arc<dyn Any + Send + Sync>),
|
186
|
+
};
|
187
|
+
|
188
|
+
self.inner
|
189
|
+
.clone()
|
190
|
+
.rolling_std_by(by.inner.clone(), options)
|
191
|
+
.into()
|
192
|
+
}
|
193
|
+
|
194
|
+
pub fn rolling_var(
|
195
|
+
&self,
|
196
|
+
window_size: usize,
|
123
197
|
weights: Option<Vec<f64>>,
|
124
198
|
min_periods: usize,
|
125
199
|
center: bool,
|
126
|
-
by: Option<String>,
|
127
|
-
closed: Option<Wrap<ClosedWindow>>,
|
128
200
|
ddof: u8,
|
129
|
-
warn_if_unsorted: bool,
|
130
201
|
) -> Self {
|
131
|
-
let options =
|
132
|
-
window_size
|
202
|
+
let options = RollingOptionsFixedWindow {
|
203
|
+
window_size,
|
133
204
|
weights,
|
134
205
|
min_periods,
|
135
206
|
center,
|
136
|
-
by,
|
137
|
-
closed_window: closed.map(|c| c.0),
|
138
207
|
fn_params: Some(Arc::new(RollingVarParams { ddof }) as Arc<dyn Any + Send + Sync>),
|
139
|
-
warn_if_unsorted,
|
140
208
|
};
|
141
209
|
|
142
210
|
self.inner.clone().rolling_var(options).into()
|
143
211
|
}
|
144
212
|
|
145
|
-
|
146
|
-
pub fn rolling_median(
|
213
|
+
pub fn rolling_var_by(
|
147
214
|
&self,
|
215
|
+
by: &RbExpr,
|
148
216
|
window_size: String,
|
217
|
+
min_periods: usize,
|
218
|
+
closed: Wrap<ClosedWindow>,
|
219
|
+
ddof: u8,
|
220
|
+
) -> Self {
|
221
|
+
let options = RollingOptionsDynamicWindow {
|
222
|
+
window_size: Duration::parse(&window_size),
|
223
|
+
min_periods,
|
224
|
+
closed_window: closed.0,
|
225
|
+
fn_params: Some(Arc::new(RollingVarParams { ddof }) as Arc<dyn Any + Send + Sync>),
|
226
|
+
};
|
227
|
+
|
228
|
+
self.inner
|
229
|
+
.clone()
|
230
|
+
.rolling_var_by(by.inner.clone(), options)
|
231
|
+
.into()
|
232
|
+
}
|
233
|
+
|
234
|
+
pub fn rolling_median(
|
235
|
+
&self,
|
236
|
+
window_size: usize,
|
149
237
|
weights: Option<Vec<f64>>,
|
150
238
|
min_periods: usize,
|
151
239
|
center: bool,
|
152
|
-
by: Option<String>,
|
153
|
-
closed: Option<Wrap<ClosedWindow>>,
|
154
|
-
warn_if_unsorted: bool,
|
155
240
|
) -> Self {
|
156
|
-
let options =
|
157
|
-
window_size
|
158
|
-
weights,
|
241
|
+
let options = RollingOptionsFixedWindow {
|
242
|
+
window_size,
|
159
243
|
min_periods,
|
244
|
+
weights,
|
160
245
|
center,
|
161
|
-
by,
|
162
|
-
closed_window: closed.map(|c| c.0),
|
163
246
|
fn_params: None,
|
164
|
-
warn_if_unsorted,
|
165
247
|
};
|
166
248
|
self.inner.clone().rolling_median(options).into()
|
167
249
|
}
|
168
250
|
|
169
|
-
|
251
|
+
pub fn rolling_median_by(
|
252
|
+
&self,
|
253
|
+
by: &RbExpr,
|
254
|
+
window_size: String,
|
255
|
+
min_periods: usize,
|
256
|
+
closed: Wrap<ClosedWindow>,
|
257
|
+
) -> Self {
|
258
|
+
let options = RollingOptionsDynamicWindow {
|
259
|
+
window_size: Duration::parse(&window_size),
|
260
|
+
min_periods,
|
261
|
+
closed_window: closed.0,
|
262
|
+
fn_params: None,
|
263
|
+
};
|
264
|
+
self.inner
|
265
|
+
.clone()
|
266
|
+
.rolling_median_by(by.inner.clone(), options)
|
267
|
+
.into()
|
268
|
+
}
|
269
|
+
|
170
270
|
pub fn rolling_quantile(
|
171
271
|
&self,
|
172
272
|
quantile: f64,
|
173
273
|
interpolation: Wrap<QuantileInterpolOptions>,
|
174
|
-
window_size:
|
274
|
+
window_size: usize,
|
175
275
|
weights: Option<Vec<f64>>,
|
176
276
|
min_periods: usize,
|
177
277
|
center: bool,
|
178
|
-
by: Option<String>,
|
179
|
-
closed: Option<Wrap<ClosedWindow>>,
|
180
|
-
warn_if_unsorted: bool,
|
181
278
|
) -> Self {
|
182
|
-
let options =
|
183
|
-
window_size
|
279
|
+
let options = RollingOptionsFixedWindow {
|
280
|
+
window_size,
|
184
281
|
weights,
|
185
282
|
min_periods,
|
186
283
|
center,
|
187
|
-
by,
|
188
|
-
closed_window: closed.map(|c| c.0),
|
189
284
|
fn_params: None,
|
190
|
-
warn_if_unsorted,
|
191
285
|
};
|
192
286
|
|
193
287
|
self.inner
|
@@ -196,6 +290,28 @@ impl RbExpr {
|
|
196
290
|
.into()
|
197
291
|
}
|
198
292
|
|
293
|
+
pub fn rolling_quantile_by(
|
294
|
+
&self,
|
295
|
+
by: &RbExpr,
|
296
|
+
quantile: f64,
|
297
|
+
interpolation: Wrap<QuantileInterpolOptions>,
|
298
|
+
window_size: String,
|
299
|
+
min_periods: usize,
|
300
|
+
closed: Wrap<ClosedWindow>,
|
301
|
+
) -> Self {
|
302
|
+
let options = RollingOptionsDynamicWindow {
|
303
|
+
window_size: Duration::parse(&window_size),
|
304
|
+
min_periods,
|
305
|
+
closed_window: closed.0,
|
306
|
+
fn_params: None,
|
307
|
+
};
|
308
|
+
|
309
|
+
self.inner
|
310
|
+
.clone()
|
311
|
+
.rolling_quantile_by(by.inner.clone(), interpolation.0, quantile, options)
|
312
|
+
.into()
|
313
|
+
}
|
314
|
+
|
199
315
|
pub fn rolling_skew(&self, window_size: usize, bias: bool) -> Self {
|
200
316
|
self.inner.clone().rolling_skew(window_size, bias).into()
|
201
317
|
}
|
@@ -244,12 +244,12 @@ impl RbExpr {
|
|
244
244
|
.into()
|
245
245
|
}
|
246
246
|
|
247
|
-
pub fn str_to_integer(&self, base:
|
247
|
+
pub fn str_to_integer(&self, base: &Self, strict: bool) -> Self {
|
248
248
|
self.inner
|
249
249
|
.clone()
|
250
250
|
.str()
|
251
|
-
.to_integer(base, strict)
|
252
|
-
.with_fmt("str.
|
251
|
+
.to_integer(base.inner.clone(), strict)
|
252
|
+
.with_fmt("str.to_integer")
|
253
253
|
.into()
|
254
254
|
}
|
255
255
|
|
@@ -259,39 +259,18 @@ impl RbExpr {
|
|
259
259
|
infer_schema_len: Option<usize>,
|
260
260
|
) -> Self {
|
261
261
|
let dtype = dtype.map(|wrap| wrap.0);
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
};
|
267
|
-
|
268
|
-
let function = move |s: Series| {
|
269
|
-
let ca = s.str()?;
|
270
|
-
match ca.json_decode(dtype.clone(), infer_schema_len) {
|
271
|
-
Ok(ca) => Ok(Some(ca.into_series())),
|
272
|
-
Err(e) => Err(PolarsError::ComputeError(format!("{e:?}").into())),
|
273
|
-
}
|
274
|
-
};
|
275
|
-
|
276
|
-
self.clone()
|
277
|
-
.inner
|
278
|
-
.map(function, output_type)
|
279
|
-
.with_fmt("str.json_decode")
|
262
|
+
self.inner
|
263
|
+
.clone()
|
264
|
+
.str()
|
265
|
+
.json_decode(dtype, infer_schema_len)
|
280
266
|
.into()
|
281
267
|
}
|
282
268
|
|
283
|
-
pub fn str_json_path_match(&self, pat:
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
Err(e) => Err(PolarsError::ComputeError(format!("{:?}", e).into())),
|
289
|
-
}
|
290
|
-
};
|
291
|
-
self.clone()
|
292
|
-
.inner
|
293
|
-
.map(function, GetOutput::from_type(DataType::String))
|
294
|
-
.with_fmt("str.json_path_match")
|
269
|
+
pub fn str_json_path_match(&self, pat: &Self) -> Self {
|
270
|
+
self.inner
|
271
|
+
.clone()
|
272
|
+
.str()
|
273
|
+
.json_path_match(pat.inner.clone())
|
295
274
|
.into()
|
296
275
|
}
|
297
276
|
|
data/ext/polars/src/file.rs
CHANGED
@@ -1,20 +1,167 @@
|
|
1
|
-
use magnus::{exception, prelude::*, Error, RString, Value};
|
2
|
-
use polars::io::mmap::MmapBytesReader;
|
3
1
|
use std::fs::File;
|
4
|
-
use std::io
|
2
|
+
use std::io;
|
3
|
+
use std::io::{BufReader, Cursor, Read, Seek, SeekFrom, Write};
|
5
4
|
use std::path::PathBuf;
|
6
5
|
|
6
|
+
use magnus::{exception, prelude::*, Error, RString, Value};
|
7
|
+
use polars::io::mmap::MmapBytesReader;
|
8
|
+
|
9
|
+
use crate::error::RbPolarsErr;
|
10
|
+
use crate::prelude::resolve_homedir;
|
7
11
|
use crate::RbResult;
|
8
12
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
#[derive(Clone)]
|
14
|
+
pub struct RbFileLikeObject {
|
15
|
+
inner: Value,
|
16
|
+
}
|
17
|
+
|
18
|
+
/// Wraps a `Value`, and implements read, seek, and write for it.
|
19
|
+
impl RbFileLikeObject {
|
20
|
+
/// Creates an instance of a `RbFileLikeObject` from a `Value`.
|
21
|
+
/// To assert the object has the required methods methods,
|
22
|
+
/// instantiate it with `RbFileLikeObject::require`
|
23
|
+
pub fn new(object: Value) -> Self {
|
24
|
+
RbFileLikeObject { inner: object }
|
25
|
+
}
|
26
|
+
|
27
|
+
pub fn as_buffer(&self) -> std::io::Cursor<Vec<u8>> {
|
28
|
+
let data = self.as_file_buffer().into_inner();
|
29
|
+
std::io::Cursor::new(data)
|
30
|
+
}
|
31
|
+
|
32
|
+
pub fn as_file_buffer(&self) -> Cursor<Vec<u8>> {
|
33
|
+
let bytes = self
|
34
|
+
.inner
|
35
|
+
.funcall::<_, _, RString>("read", ())
|
36
|
+
.expect("no read method found");
|
37
|
+
|
38
|
+
let buf = unsafe { bytes.as_slice() }.to_vec();
|
39
|
+
|
40
|
+
Cursor::new(buf)
|
41
|
+
}
|
42
|
+
|
43
|
+
/// Same as `RbFileLikeObject::new`, but validates that the underlying
|
44
|
+
/// ruby object has a `read`, `write`, and `seek` methods in respect to parameters.
|
45
|
+
/// Will return a `TypeError` if object does not have `read`, `seek`, and `write` methods.
|
46
|
+
pub fn with_requirements(object: Value, read: bool, write: bool, seek: bool) -> RbResult<Self> {
|
47
|
+
if read && !object.respond_to("read", false)? {
|
48
|
+
return Err(Error::new(
|
49
|
+
exception::type_error(),
|
50
|
+
"Object does not have a .read() method.",
|
51
|
+
));
|
52
|
+
}
|
53
|
+
|
54
|
+
if seek && !object.respond_to("seek", false)? {
|
55
|
+
return Err(Error::new(
|
56
|
+
exception::type_error(),
|
57
|
+
"Object does not have a .seek() method.",
|
58
|
+
));
|
59
|
+
}
|
60
|
+
|
61
|
+
if write && !object.respond_to("write", false)? {
|
62
|
+
return Err(Error::new(
|
63
|
+
exception::type_error(),
|
64
|
+
"Object does not have a .write() method.",
|
65
|
+
));
|
66
|
+
}
|
67
|
+
|
68
|
+
Ok(RbFileLikeObject::new(object))
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
/// Extracts a string repr from, and returns an IO error to send back to rust.
|
73
|
+
fn rberr_to_io_err(e: Error) -> io::Error {
|
74
|
+
io::Error::new(io::ErrorKind::Other, e.to_string())
|
75
|
+
}
|
76
|
+
|
77
|
+
impl Read for RbFileLikeObject {
|
78
|
+
fn read(&mut self, mut buf: &mut [u8]) -> Result<usize, io::Error> {
|
79
|
+
let bytes = self
|
80
|
+
.inner
|
81
|
+
.funcall::<_, _, RString>("read", (buf.len(),))
|
82
|
+
.map_err(rberr_to_io_err)?;
|
83
|
+
|
84
|
+
buf.write_all(unsafe { bytes.as_slice() })?;
|
85
|
+
|
86
|
+
Ok(bytes.len())
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
impl Write for RbFileLikeObject {
|
91
|
+
fn write(&mut self, buf: &[u8]) -> Result<usize, io::Error> {
|
92
|
+
let rbbytes = RString::from_slice(buf);
|
93
|
+
|
94
|
+
let number_bytes_written = self
|
95
|
+
.inner
|
96
|
+
.funcall::<_, _, usize>("write", (rbbytes,))
|
97
|
+
.map_err(rberr_to_io_err)?;
|
98
|
+
|
99
|
+
Ok(number_bytes_written)
|
100
|
+
}
|
101
|
+
|
102
|
+
fn flush(&mut self) -> Result<(), io::Error> {
|
103
|
+
self.inner
|
104
|
+
.funcall::<_, _, Value>("flush", ())
|
105
|
+
.map_err(rberr_to_io_err)?;
|
106
|
+
|
107
|
+
Ok(())
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
impl Seek for RbFileLikeObject {
|
112
|
+
fn seek(&mut self, pos: SeekFrom) -> Result<u64, io::Error> {
|
113
|
+
let (whence, offset) = match pos {
|
114
|
+
SeekFrom::Start(i) => (0, i as i64),
|
115
|
+
SeekFrom::Current(i) => (1, i),
|
116
|
+
SeekFrom::End(i) => (2, i),
|
117
|
+
};
|
118
|
+
|
119
|
+
let new_position = self
|
120
|
+
.inner
|
121
|
+
.funcall("seek", (offset, whence))
|
122
|
+
.map_err(rberr_to_io_err)?;
|
123
|
+
|
124
|
+
Ok(new_position)
|
125
|
+
}
|
126
|
+
}
|
127
|
+
|
128
|
+
pub trait FileLike: Read + Write + Seek {}
|
129
|
+
|
130
|
+
impl FileLike for File {}
|
131
|
+
impl FileLike for RbFileLikeObject {}
|
132
|
+
|
133
|
+
pub enum EitherRustRubyFile {
|
134
|
+
Rb(RbFileLikeObject),
|
135
|
+
Rust(BufReader<File>),
|
136
|
+
}
|
137
|
+
|
138
|
+
///
|
139
|
+
/// # Arguments
|
140
|
+
/// * `truncate` - open or create a new file.
|
141
|
+
pub fn get_either_file(rb_f: Value, truncate: bool) -> RbResult<EitherRustRubyFile> {
|
142
|
+
if let Ok(rstring) = RString::try_convert(rb_f) {
|
143
|
+
let s = unsafe { rstring.as_str() }?;
|
144
|
+
let file_path = std::path::Path::new(&s);
|
145
|
+
let file_path = resolve_homedir(file_path);
|
146
|
+
let f = if truncate {
|
147
|
+
File::create(file_path).map_err(RbPolarsErr::io)?
|
148
|
+
} else {
|
149
|
+
polars_utils::open_file(&file_path).map_err(RbPolarsErr::from)?
|
150
|
+
};
|
151
|
+
let reader = BufReader::new(f);
|
152
|
+
Ok(EitherRustRubyFile::Rust(reader))
|
14
153
|
} else {
|
15
|
-
|
16
|
-
|
17
|
-
|
154
|
+
let f = RbFileLikeObject::with_requirements(rb_f, !truncate, truncate, !truncate)?;
|
155
|
+
Ok(EitherRustRubyFile::Rb(f))
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
pub fn get_file_like(f: Value, truncate: bool) -> RbResult<Box<dyn FileLike>> {
|
160
|
+
use EitherRustRubyFile::*;
|
161
|
+
match get_either_file(f, truncate)? {
|
162
|
+
Rb(f) => Ok(Box::new(f)),
|
163
|
+
Rust(f) => Ok(Box::new(f.into_inner())),
|
164
|
+
}
|
18
165
|
}
|
19
166
|
|
20
167
|
pub fn get_mmap_bytes_reader(rb_f: Value) -> RbResult<Box<dyn MmapBytesReader>> {
|
@@ -55,9 +55,24 @@ pub fn rolling_cov(
|
|
55
55
|
.into()
|
56
56
|
}
|
57
57
|
|
58
|
-
pub fn arg_sort_by(
|
58
|
+
pub fn arg_sort_by(
|
59
|
+
by: RArray,
|
60
|
+
descending: Vec<bool>,
|
61
|
+
nulls_last: bool,
|
62
|
+
multithreaded: bool,
|
63
|
+
maintain_order: bool,
|
64
|
+
) -> RbResult<RbExpr> {
|
59
65
|
let by = rb_exprs_to_exprs(by)?;
|
60
|
-
Ok(dsl::arg_sort_by(
|
66
|
+
Ok(dsl::arg_sort_by(
|
67
|
+
by,
|
68
|
+
SortMultipleOptions {
|
69
|
+
descending,
|
70
|
+
nulls_last,
|
71
|
+
multithreaded,
|
72
|
+
maintain_order,
|
73
|
+
},
|
74
|
+
)
|
75
|
+
.into())
|
61
76
|
}
|
62
77
|
|
63
78
|
pub fn arg_where(condition: &RbExpr) -> RbExpr {
|
@@ -115,6 +130,7 @@ pub fn concat_lf(
|
|
115
130
|
rechunk,
|
116
131
|
parallel,
|
117
132
|
to_supertypes,
|
133
|
+
..Default::default()
|
118
134
|
},
|
119
135
|
)
|
120
136
|
.map_err(RbPolarsErr::from)?;
|
@@ -183,6 +199,7 @@ pub fn concat_lf_diagonal(
|
|
183
199
|
rechunk,
|
184
200
|
parallel,
|
185
201
|
to_supertypes,
|
202
|
+
..Default::default()
|
186
203
|
},
|
187
204
|
)
|
188
205
|
.map_err(RbPolarsErr::from)?;
|
@@ -324,6 +341,6 @@ pub fn spearman_rank_corr(a: &RbExpr, b: &RbExpr, ddof: u8, propagate_nans: bool
|
|
324
341
|
}
|
325
342
|
|
326
343
|
pub fn sql_expr(sql: String) -> RbResult<RbExpr> {
|
327
|
-
let expr = polars::sql::sql_expr(
|
344
|
+
let expr = polars::sql::sql_expr(sql).map_err(RbPolarsErr::from)?;
|
328
345
|
Ok(expr.into())
|
329
346
|
}
|