polars-df 0.23.0 → 0.24.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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +127 -1
  3. data/Cargo.lock +72 -58
  4. data/README.md +31 -27
  5. data/ext/polars/Cargo.toml +15 -6
  6. data/ext/polars/src/batched_csv.rs +35 -39
  7. data/ext/polars/src/c_api/allocator.rs +7 -0
  8. data/ext/polars/src/c_api/mod.rs +1 -0
  9. data/ext/polars/src/catalog/unity.rs +123 -101
  10. data/ext/polars/src/conversion/any_value.rs +13 -17
  11. data/ext/polars/src/conversion/chunked_array.rs +5 -5
  12. data/ext/polars/src/conversion/datetime.rs +3 -2
  13. data/ext/polars/src/conversion/mod.rs +50 -45
  14. data/ext/polars/src/dataframe/export.rs +13 -13
  15. data/ext/polars/src/dataframe/general.rs +223 -223
  16. data/ext/polars/src/dataframe/io.rs +27 -141
  17. data/ext/polars/src/dataframe/mod.rs +13 -5
  18. data/ext/polars/src/dataframe/serde.rs +1 -1
  19. data/ext/polars/src/error.rs +44 -7
  20. data/ext/polars/src/exceptions.rs +45 -12
  21. data/ext/polars/src/expr/array.rs +12 -0
  22. data/ext/polars/src/expr/datatype.rs +2 -2
  23. data/ext/polars/src/expr/datetime.rs +4 -5
  24. data/ext/polars/src/expr/general.rs +49 -13
  25. data/ext/polars/src/expr/list.rs +4 -0
  26. data/ext/polars/src/expr/meta.rs +8 -3
  27. data/ext/polars/src/expr/mod.rs +22 -6
  28. data/ext/polars/src/expr/name.rs +19 -8
  29. data/ext/polars/src/expr/rolling.rs +50 -1
  30. data/ext/polars/src/expr/string.rs +0 -1
  31. data/ext/polars/src/expr/struct.rs +7 -2
  32. data/ext/polars/src/file.rs +136 -103
  33. data/ext/polars/src/functions/aggregation.rs +9 -8
  34. data/ext/polars/src/functions/io.rs +81 -10
  35. data/ext/polars/src/functions/lazy.rs +95 -21
  36. data/ext/polars/src/functions/mod.rs +2 -0
  37. data/ext/polars/src/functions/range.rs +19 -3
  38. data/ext/polars/src/functions/strings.rs +6 -0
  39. data/ext/polars/src/functions/utils.rs +6 -0
  40. data/ext/polars/src/interop/arrow/mod.rs +50 -1
  41. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +30 -0
  42. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  43. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  44. data/ext/polars/src/interop/numo/to_numo_series.rs +1 -1
  45. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  46. data/ext/polars/src/lazyframe/general.rs +340 -236
  47. data/ext/polars/src/lazyframe/mod.rs +46 -10
  48. data/ext/polars/src/lazyframe/optflags.rs +5 -4
  49. data/ext/polars/src/lazyframe/serde.rs +11 -3
  50. data/ext/polars/src/lazyframe/sink.rs +10 -5
  51. data/ext/polars/src/lazygroupby.rs +6 -7
  52. data/ext/polars/src/lib.rs +141 -76
  53. data/ext/polars/src/map/dataframe.rs +12 -12
  54. data/ext/polars/src/map/lazy.rs +7 -5
  55. data/ext/polars/src/map/mod.rs +15 -8
  56. data/ext/polars/src/map/series.rs +3 -3
  57. data/ext/polars/src/on_startup.rs +16 -8
  58. data/ext/polars/src/prelude.rs +1 -0
  59. data/ext/polars/src/rb_modules.rs +19 -49
  60. data/ext/polars/src/series/aggregation.rs +79 -140
  61. data/ext/polars/src/series/arithmetic.rs +16 -22
  62. data/ext/polars/src/series/comparison.rs +101 -222
  63. data/ext/polars/src/series/construction.rs +17 -18
  64. data/ext/polars/src/series/export.rs +1 -1
  65. data/ext/polars/src/series/general.rs +254 -289
  66. data/ext/polars/src/series/import.rs +17 -0
  67. data/ext/polars/src/series/map.rs +178 -160
  68. data/ext/polars/src/series/mod.rs +28 -12
  69. data/ext/polars/src/series/scatter.rs +12 -9
  70. data/ext/polars/src/sql.rs +16 -9
  71. data/ext/polars/src/testing/frame.rs +31 -0
  72. data/ext/polars/src/testing/mod.rs +5 -0
  73. data/ext/polars/src/testing/series.rs +31 -0
  74. data/ext/polars/src/timeout.rs +105 -0
  75. data/ext/polars/src/utils.rs +159 -1
  76. data/lib/polars/array_expr.rb +81 -12
  77. data/lib/polars/array_name_space.rb +74 -7
  78. data/lib/polars/batched_csv_reader.rb +21 -21
  79. data/lib/polars/binary_name_space.rb +1 -1
  80. data/lib/polars/cat_expr.rb +7 -7
  81. data/lib/polars/config.rb +1 -1
  82. data/lib/polars/convert.rb +189 -34
  83. data/lib/polars/data_frame.rb +1066 -831
  84. data/lib/polars/data_frame_plot.rb +173 -0
  85. data/lib/polars/data_type_group.rb +1 -0
  86. data/lib/polars/data_types.rb +31 -12
  87. data/lib/polars/date_time_expr.rb +51 -69
  88. data/lib/polars/date_time_name_space.rb +80 -112
  89. data/lib/polars/dynamic_group_by.rb +7 -7
  90. data/lib/polars/exceptions.rb +50 -10
  91. data/lib/polars/expr.rb +470 -517
  92. data/lib/polars/functions/aggregation/horizontal.rb +0 -1
  93. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  94. data/lib/polars/functions/as_datatype.rb +290 -8
  95. data/lib/polars/functions/eager.rb +204 -10
  96. data/lib/polars/functions/escape_regex.rb +21 -0
  97. data/lib/polars/functions/lazy.rb +409 -169
  98. data/lib/polars/functions/lit.rb +17 -1
  99. data/lib/polars/functions/range/int_range.rb +74 -2
  100. data/lib/polars/functions/range/linear_space.rb +77 -0
  101. data/lib/polars/functions/range/time_range.rb +1 -1
  102. data/lib/polars/functions/repeat.rb +3 -12
  103. data/lib/polars/functions/whenthen.rb +2 -2
  104. data/lib/polars/group_by.rb +72 -20
  105. data/lib/polars/iceberg_dataset.rb +1 -6
  106. data/lib/polars/in_process_query.rb +37 -0
  107. data/lib/polars/io/cloud.rb +18 -0
  108. data/lib/polars/io/csv.rb +265 -126
  109. data/lib/polars/io/database.rb +0 -1
  110. data/lib/polars/io/delta.rb +15 -7
  111. data/lib/polars/io/ipc.rb +24 -17
  112. data/lib/polars/io/ndjson.rb +161 -24
  113. data/lib/polars/io/parquet.rb +101 -38
  114. data/lib/polars/lazy_frame.rb +849 -558
  115. data/lib/polars/lazy_group_by.rb +327 -2
  116. data/lib/polars/list_expr.rb +94 -16
  117. data/lib/polars/list_name_space.rb +88 -24
  118. data/lib/polars/meta_expr.rb +42 -1
  119. data/lib/polars/name_expr.rb +41 -4
  120. data/lib/polars/query_opt_flags.rb +198 -2
  121. data/lib/polars/rolling_group_by.rb +3 -3
  122. data/lib/polars/schema.rb +21 -3
  123. data/lib/polars/selector.rb +37 -2
  124. data/lib/polars/selectors.rb +45 -9
  125. data/lib/polars/series.rb +1156 -728
  126. data/lib/polars/series_plot.rb +72 -0
  127. data/lib/polars/slice.rb +1 -1
  128. data/lib/polars/sql_context.rb +11 -4
  129. data/lib/polars/string_expr.rb +59 -68
  130. data/lib/polars/string_name_space.rb +51 -87
  131. data/lib/polars/struct_expr.rb +36 -18
  132. data/lib/polars/testing.rb +24 -273
  133. data/lib/polars/utils/constants.rb +2 -0
  134. data/lib/polars/utils/construction/data_frame.rb +410 -0
  135. data/lib/polars/utils/construction/series.rb +364 -0
  136. data/lib/polars/utils/construction/utils.rb +9 -0
  137. data/lib/polars/utils/deprecation.rb +11 -0
  138. data/lib/polars/utils/serde.rb +8 -3
  139. data/lib/polars/utils/unstable.rb +19 -0
  140. data/lib/polars/utils/various.rb +59 -0
  141. data/lib/polars/utils.rb +46 -47
  142. data/lib/polars/version.rb +1 -1
  143. data/lib/polars.rb +47 -1
  144. metadata +25 -6
  145. data/ext/polars/src/allocator.rs +0 -13
  146. data/lib/polars/plot.rb +0 -109
@@ -1,23 +1,22 @@
1
- use magnus::{Error, IntoValue, RArray, Ruby, Value, value::ReprValue};
1
+ use magnus::{IntoValue, RArray, Ruby, Value, value::ReprValue};
2
2
  use polars::prelude::*;
3
3
  use polars::series::IsSorted;
4
+ use polars_core::chunked_array::cast::CastOptions;
4
5
  use polars_core::utils::flatten::flatten_series;
5
6
 
6
7
  use crate::conversion::*;
7
- use crate::exceptions::RbIndexError;
8
- use crate::rb_modules;
8
+ use crate::exceptions::{RbIndexError, RbRuntimeError, RbValueError};
9
+ use crate::prelude::*;
10
+ use crate::utils::{EnterPolarsExt, RubyAttach};
9
11
  use crate::{RbDataFrame, RbErr, RbPolarsErr, RbResult, RbSeries};
10
12
 
11
13
  impl RbSeries {
12
- pub fn struct_unnest(&self) -> RbResult<RbDataFrame> {
13
- let binding = self.series.borrow();
14
- let ca = binding.struct_().map_err(RbPolarsErr::from)?;
15
- let df: DataFrame = ca.clone().unnest();
16
- Ok(df.into())
14
+ pub fn struct_unnest(rb: &Ruby, self_: &Self) -> RbResult<RbDataFrame> {
15
+ rb.enter_polars_df(|| Ok(self_.series.read().struct_()?.clone().unnest()))
17
16
  }
18
17
 
19
18
  pub fn struct_fields(&self) -> RbResult<Vec<String>> {
20
- let binding = self.series.borrow();
19
+ let binding = self.series.read();
21
20
  let ca = binding.struct_().map_err(RbPolarsErr::from)?;
22
21
  Ok(ca
23
22
  .struct_fields()
@@ -27,15 +26,15 @@ impl RbSeries {
27
26
  }
28
27
 
29
28
  pub fn is_sorted_ascending_flag(&self) -> bool {
30
- matches!(self.series.borrow().is_sorted_flag(), IsSorted::Ascending)
29
+ matches!(self.series.read().is_sorted_flag(), IsSorted::Ascending)
31
30
  }
32
31
 
33
32
  pub fn is_sorted_descending_flag(&self) -> bool {
34
- matches!(self.series.borrow().is_sorted_flag(), IsSorted::Descending)
33
+ matches!(self.series.read().is_sorted_flag(), IsSorted::Descending)
35
34
  }
36
35
 
37
36
  pub fn can_fast_explode_flag(&self) -> bool {
38
- match self.series.borrow().list() {
37
+ match self.series.read().list() {
39
38
  Err(_) => false,
40
39
  Ok(list) => list._can_fast_explode(),
41
40
  }
@@ -54,12 +53,21 @@ impl RbSeries {
54
53
  }
55
54
 
56
55
  pub fn estimated_size(&self) -> usize {
57
- self.series.borrow().estimated_size()
56
+ self.series.read().estimated_size()
57
+ }
58
+
59
+ pub fn reshape(rb: &Ruby, self_: &Self, dims: Vec<i64>) -> RbResult<Self> {
60
+ let dims = dims
61
+ .into_iter()
62
+ .map(ReshapeDimension::new)
63
+ .collect::<Vec<_>>();
64
+
65
+ rb.enter_polars_series(|| self_.series.read().reshape_array(&dims))
58
66
  }
59
67
 
60
68
  pub fn get_fmt(&self, index: usize, str_lengths: usize) -> String {
61
- let val = format!("{}", self.series.borrow().get(index).unwrap());
62
- if let DataType::String | DataType::Categorical(_, _) = self.series.borrow().dtype() {
69
+ let val = format!("{}", self.series.read().get(index).unwrap());
70
+ if let DataType::String | DataType::Categorical(_, _) = self.series.read().dtype() {
63
71
  let v_trunc = &val[..val
64
72
  .char_indices()
65
73
  .take(str_lengths)
@@ -76,18 +84,18 @@ impl RbSeries {
76
84
  }
77
85
  }
78
86
 
79
- pub fn rechunk(&self, in_place: bool) -> Option<Self> {
80
- let series = self.series.borrow_mut().rechunk();
87
+ pub fn rechunk(rb: &Ruby, self_: &Self, in_place: bool) -> RbResult<Option<Self>> {
88
+ let series = rb.enter_polars_ok(|| self_.series.read().rechunk())?;
81
89
  if in_place {
82
- *self.series.borrow_mut() = series;
83
- None
90
+ *self_.series.write() = series;
91
+ Ok(None)
84
92
  } else {
85
- Some(series.into())
93
+ Ok(Some(series.into()))
86
94
  }
87
95
  }
88
96
 
89
- pub fn get_index(ruby: &Ruby, rb_self: &Self, index: usize) -> RbResult<Value> {
90
- let binding = rb_self.series.borrow();
97
+ pub fn get_index(ruby: &Ruby, self_: &Self, index: usize) -> RbResult<Value> {
98
+ let binding = self_.series.read();
91
99
  let av = match binding.get(index) {
92
100
  Ok(v) => v,
93
101
  Err(PolarsError::OutOfBounds(err)) => {
@@ -99,70 +107,58 @@ impl RbSeries {
99
107
  match av {
100
108
  AnyValue::List(s) | AnyValue::Array(s, _) => {
101
109
  let rbseries = RbSeries::new(s);
102
- rb_modules::pl_utils().funcall("wrap_s", (rbseries,))
110
+ rb_modules::pl_utils(ruby).funcall("wrap_s", (rbseries,))
103
111
  }
104
112
  _ => Ok(Wrap(av).into_value_with(ruby)),
105
113
  }
106
114
  }
107
115
 
108
- pub fn get_index_signed(ruby: &Ruby, rb_self: &Self, index: isize) -> RbResult<Value> {
116
+ pub fn get_index_signed(ruby: &Ruby, self_: &Self, index: isize) -> RbResult<Value> {
109
117
  let index = if index < 0 {
110
- match rb_self.len().checked_sub(index.unsigned_abs()) {
118
+ match self_.len().checked_sub(index.unsigned_abs()) {
111
119
  Some(v) => v,
112
120
  None => {
113
121
  return Err(RbIndexError::new_err(
114
- polars_err!(oob = index, rb_self.len()).to_string(),
122
+ polars_err!(oob = index, self_.len()).to_string(),
115
123
  ));
116
124
  }
117
125
  }
118
126
  } else {
119
127
  usize::try_from(index).unwrap()
120
128
  };
121
- Self::get_index(ruby, rb_self, index)
129
+ Self::get_index(ruby, self_, index)
122
130
  }
123
131
 
124
- pub fn bitand(&self, other: &RbSeries) -> RbResult<Self> {
125
- let out = (&*self.series.borrow() & &*other.series.borrow()).map_err(RbPolarsErr::from)?;
126
- Ok(out.into())
132
+ pub fn bitand(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
133
+ rb.enter_polars_series(|| &*self_.series.read() & &*other.series.read())
127
134
  }
128
135
 
129
- pub fn bitor(&self, other: &RbSeries) -> RbResult<Self> {
130
- let out = (&*self.series.borrow() | &*other.series.borrow()).map_err(RbPolarsErr::from)?;
131
- Ok(out.into())
136
+ pub fn bitor(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
137
+ rb.enter_polars_series(|| &*self_.series.read() | &*other.series.read())
132
138
  }
133
139
 
134
- pub fn bitxor(&self, other: &RbSeries) -> RbResult<Self> {
135
- let out = (&*self.series.borrow() ^ &*other.series.borrow()).map_err(RbPolarsErr::from)?;
136
- Ok(out.into())
140
+ pub fn bitxor(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
141
+ rb.enter_polars_series(|| &*self_.series.read() ^ &*other.series.read())
137
142
  }
138
143
 
139
144
  pub fn chunk_lengths(&self) -> Vec<usize> {
140
- self.series.borrow().chunk_lengths().collect()
145
+ self.series.read().chunk_lengths().collect()
141
146
  }
142
147
 
143
148
  pub fn name(&self) -> String {
144
- self.series.borrow().name().to_string()
149
+ self.series.read().name().to_string()
145
150
  }
146
151
 
147
152
  pub fn rename(&self, name: String) {
148
- self.series.borrow_mut().rename(name.into());
153
+ self.series.write().rename(name.into());
149
154
  }
150
155
 
151
- pub fn dtype(ruby: &Ruby, rb_self: &Self) -> Value {
152
- Wrap(rb_self.series.borrow().dtype().clone()).into_value_with(ruby)
153
- }
154
-
155
- pub fn inner_dtype(ruby: &Ruby, rb_self: &Self) -> Option<Value> {
156
- rb_self
157
- .series
158
- .borrow()
159
- .dtype()
160
- .inner_dtype()
161
- .map(|dt| Wrap(dt.clone()).into_value_with(ruby))
156
+ pub fn dtype(rb: &Ruby, self_: &Self) -> Value {
157
+ Wrap(self_.series.read().dtype().clone()).into_value_with(rb)
162
158
  }
163
159
 
164
160
  pub fn set_sorted_flag(&self, descending: bool) -> Self {
165
- let mut out = self.series.borrow().clone();
161
+ let mut out = self.series.read().clone();
166
162
  if descending {
167
163
  out.set_sorted_flag(IsSorted::Descending);
168
164
  } else {
@@ -172,284 +168,207 @@ impl RbSeries {
172
168
  }
173
169
 
174
170
  pub fn n_chunks(&self) -> usize {
175
- self.series.borrow().n_chunks()
171
+ self.series.read().n_chunks()
176
172
  }
177
173
 
178
- pub fn append(ruby: &Ruby, rb_self: &Self, other: &RbSeries) -> RbResult<()> {
179
- let mut binding = rb_self.series.borrow_mut();
180
- let res = binding.append(&other.series.borrow());
181
- if let Err(e) = res {
182
- Err(Error::new(ruby.exception_runtime_error(), e.to_string()))
183
- } else {
184
- Ok(())
185
- }
174
+ pub fn append(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<()> {
175
+ rb.enter_polars(|| {
176
+ // Prevent self-append deadlocks.
177
+ let other = other.series.read().clone();
178
+ let mut s = self_.series.write();
179
+ s.append(&other)?;
180
+ PolarsResult::Ok(())
181
+ })
186
182
  }
187
183
 
188
- pub fn extend(&self, other: &RbSeries) -> RbResult<()> {
189
- self.series
190
- .borrow_mut()
191
- .extend(&other.series.borrow())
192
- .map_err(RbPolarsErr::from)?;
193
- Ok(())
184
+ pub fn extend(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<()> {
185
+ rb.enter_polars(|| {
186
+ // Prevent self-extend deadlocks.
187
+ let other = other.series.read().clone();
188
+ let mut s = self_.series.write();
189
+ s.extend(&other)?;
190
+ PolarsResult::Ok(())
191
+ })
194
192
  }
195
193
 
196
- pub fn new_from_index(
197
- ruby: &Ruby,
198
- rb_self: &Self,
199
- index: usize,
200
- length: usize,
201
- ) -> RbResult<Self> {
202
- if index >= rb_self.series.borrow().len() {
203
- Err(Error::new(
204
- ruby.exception_arg_error(),
205
- "index is out of bounds",
206
- ))
194
+ pub fn new_from_index(rb: &Ruby, self_: &Self, index: usize, length: usize) -> RbResult<Self> {
195
+ let s = self_.series.read();
196
+ if index >= s.len() {
197
+ Err(RbValueError::new_err("index is out of bounds"))
207
198
  } else {
208
- Ok(rb_self.series.borrow().new_from_index(index, length).into())
199
+ rb.enter_polars_series(|| Ok(s.new_from_index(index, length)))
209
200
  }
210
201
  }
211
202
 
212
- pub fn filter(ruby: &Ruby, rb_self: &Self, filter: &RbSeries) -> RbResult<Self> {
213
- let filter_series = &filter.series.borrow();
203
+ pub fn filter(rb: &Ruby, self_: &Self, filter: &RbSeries) -> RbResult<Self> {
204
+ let filter_series = &filter.series.read();
214
205
  if let Ok(ca) = filter_series.bool() {
215
- let series = rb_self.series.borrow().filter(ca).unwrap();
216
- Ok(series.into())
206
+ rb.enter_polars_series(|| self_.series.read().filter(ca))
217
207
  } else {
218
- Err(Error::new(
219
- ruby.exception_runtime_error(),
220
- "Expected a boolean mask".to_string(),
221
- ))
208
+ Err(RbRuntimeError::new_err("Expected a boolean mask"))
222
209
  }
223
210
  }
224
211
 
225
- pub fn sort(&self, descending: bool, nulls_last: bool, multithreaded: bool) -> RbResult<Self> {
226
- Ok(self
227
- .series
228
- .borrow_mut()
229
- .sort(
212
+ pub fn sort(
213
+ rb: &Ruby,
214
+ self_: &Self,
215
+ descending: bool,
216
+ nulls_last: bool,
217
+ multithreaded: bool,
218
+ ) -> RbResult<Self> {
219
+ rb.enter_polars_series(|| {
220
+ self_.series.read().sort(
230
221
  SortOptions::default()
231
222
  .with_order_descending(descending)
232
223
  .with_nulls_last(nulls_last)
233
224
  .with_multithreaded(multithreaded),
234
225
  )
235
- .map_err(RbPolarsErr::from)?
236
- .into())
237
- }
238
-
239
- pub fn value_counts(
240
- &self,
241
- sort: bool,
242
- parallel: bool,
243
- name: String,
244
- normalize: bool,
245
- ) -> RbResult<RbDataFrame> {
246
- let out = self
247
- .series
248
- .borrow()
249
- .value_counts(sort, parallel, name.into(), normalize)
250
- .map_err(RbPolarsErr::from)?;
251
- Ok(out.into())
226
+ })
252
227
  }
253
228
 
254
- pub fn slice(&self, offset: i64, length: Option<usize>) -> Self {
255
- let length = length.unwrap_or_else(|| self.series.borrow().len());
256
- self.series.borrow().slice(offset, length).into()
257
- }
258
-
259
- pub fn take_with_series(&self, indices: &RbSeries) -> RbResult<Self> {
260
- let binding = indices.series.borrow();
261
- let idx = binding.idx().map_err(RbPolarsErr::from)?;
262
- let take = self.series.borrow().take(idx).map_err(RbPolarsErr::from)?;
263
- Ok(RbSeries::new(take))
229
+ pub fn gather_with_series(rb: &Ruby, self_: &Self, indices: &RbSeries) -> RbResult<Self> {
230
+ rb.enter_polars_series(|| self_.series.read().take(indices.series.read().idx()?))
264
231
  }
265
232
 
266
233
  pub fn null_count(&self) -> RbResult<usize> {
267
- Ok(self.series.borrow().null_count())
234
+ Ok(self.series.read().null_count())
268
235
  }
269
236
 
270
237
  pub fn has_nulls(&self) -> bool {
271
- self.series.borrow().has_nulls()
272
- }
273
-
274
- pub fn sample_n(
275
- &self,
276
- n: usize,
277
- with_replacement: bool,
278
- shuffle: bool,
279
- seed: Option<u64>,
280
- ) -> RbResult<Self> {
281
- let s = self
282
- .series
283
- .borrow()
284
- .sample_n(n, with_replacement, shuffle, seed)
285
- .map_err(RbPolarsErr::from)?;
286
- Ok(s.into())
287
- }
288
-
289
- pub fn sample_frac(
290
- &self,
291
- frac: f64,
292
- with_replacement: bool,
293
- shuffle: bool,
294
- seed: Option<u64>,
295
- ) -> RbResult<Self> {
296
- let s = self
297
- .series
298
- .borrow()
299
- .sample_frac(frac, with_replacement, shuffle, seed)
300
- .map_err(RbPolarsErr::from)?;
301
- Ok(s.into())
238
+ self.series.read().has_nulls()
302
239
  }
303
240
 
304
241
  pub fn equals(
305
- &self,
242
+ rb: &Ruby,
243
+ self_: &Self,
306
244
  other: &RbSeries,
307
245
  check_dtypes: bool,
308
246
  check_names: bool,
309
247
  null_equal: bool,
310
- ) -> bool {
311
- if check_dtypes && (self.series.borrow().dtype() != other.series.borrow().dtype()) {
312
- return false;
248
+ ) -> RbResult<bool> {
249
+ let s = self_.series.read();
250
+ let o = other.series.read();
251
+ if check_dtypes && (s.dtype() != o.dtype()) {
252
+ return Ok(false);
313
253
  }
314
- if check_names && (self.series.borrow().name() != other.series.borrow().name()) {
315
- return false;
254
+ if check_names && (s.name() != o.name()) {
255
+ return Ok(false);
316
256
  }
317
257
  if null_equal {
318
- self.series.borrow().equals_missing(&other.series.borrow())
258
+ rb.enter_polars_ok(|| s.equals_missing(&o))
319
259
  } else {
320
- self.series.borrow().equals(&other.series.borrow())
260
+ rb.enter_polars_ok(|| s.equals(&o))
321
261
  }
322
262
  }
323
263
 
324
- pub fn not_(&self) -> RbResult<Self> {
325
- let binding = self.series.borrow();
326
- let bool = binding.bool().map_err(RbPolarsErr::from)?;
327
- Ok((!bool).into_series().into())
328
- }
329
-
330
- pub fn shrink_dtype(&self) -> RbResult<Self> {
331
- self.series
332
- .borrow()
333
- .shrink_type()
334
- .map(Into::into)
335
- .map_err(RbPolarsErr::from)
336
- .map_err(RbErr::from)
337
- }
338
-
339
- pub fn str_to_decimal_infer(&self, inference_length: usize) -> RbResult<Self> {
340
- let s = self.series.borrow();
341
- let ca = s.str().map_err(RbPolarsErr::from)?;
342
- ca.to_decimal_infer(inference_length)
343
- .map(Into::into)
344
- .map_err(RbPolarsErr::from)
345
- .map_err(RbErr::from)
346
- }
347
-
348
- pub fn str_json_decode(&self, infer_schema_length: Option<usize>) -> RbResult<Self> {
349
- let lock = self.series.borrow();
350
- lock.str()
351
- .map_err(RbPolarsErr::from)?
352
- .json_decode(None, infer_schema_length)
353
- .map(|s| s.with_name(lock.name().clone()))
354
- .map(Into::into)
355
- .map_err(RbPolarsErr::from)
356
- .map_err(RbErr::from)
357
- }
358
-
359
- pub fn to_s(&self) -> String {
360
- format!("{}", self.series.borrow())
264
+ pub fn as_str(&self) -> String {
265
+ format!("{:?}", self.series.read())
361
266
  }
362
267
 
363
268
  pub fn len(&self) -> usize {
364
- self.series.borrow().len()
269
+ self.series.read().len()
365
270
  }
366
271
 
367
272
  pub fn clone(&self) -> Self {
368
- RbSeries::new(self.series.borrow().clone())
273
+ Clone::clone(self)
369
274
  }
370
275
 
371
- pub fn zip_with(&self, mask: &RbSeries, other: &RbSeries) -> RbResult<Self> {
372
- let binding = mask.series.borrow();
373
- let mask = binding.bool().map_err(RbPolarsErr::from)?;
374
- let s = self
375
- .series
376
- .borrow()
377
- .zip_with(mask, &other.series.borrow())
378
- .map_err(RbPolarsErr::from)?;
379
- Ok(RbSeries::new(s))
276
+ pub fn zip_with(rb: &Ruby, self_: &Self, mask: &RbSeries, other: &RbSeries) -> RbResult<Self> {
277
+ let ms = mask.series.read();
278
+ let mask = ms.bool().map_err(RbPolarsErr::from)?;
279
+ rb.enter_polars_series(|| self_.series.read().zip_with(mask, &other.series.read()))
380
280
  }
381
281
 
382
282
  pub fn to_dummies(
383
- &self,
384
- sep: Option<String>,
283
+ rb: &Ruby,
284
+ self_: &Self,
285
+ separator: Option<String>,
385
286
  drop_first: bool,
386
287
  drop_nulls: bool,
387
288
  ) -> RbResult<RbDataFrame> {
388
- let df = self
389
- .series
390
- .borrow()
391
- .to_dummies(sep.as_deref(), drop_first, drop_nulls)
392
- .map_err(RbPolarsErr::from)?;
393
- Ok(df.into())
289
+ rb.enter_polars_df(|| {
290
+ self_
291
+ .series
292
+ .read()
293
+ .to_dummies(separator.as_deref(), drop_first, drop_nulls)
294
+ })
394
295
  }
395
296
 
396
- pub fn n_unique(&self) -> RbResult<usize> {
397
- let n = self.series.borrow().n_unique().map_err(RbPolarsErr::from)?;
398
- Ok(n)
297
+ pub fn n_unique(rb: &Ruby, self_: &Self) -> RbResult<usize> {
298
+ rb.enter_polars(|| self_.series.read().n_unique())
399
299
  }
400
300
 
401
- pub fn floor(&self) -> RbResult<Self> {
402
- let s = self.series.borrow().floor().map_err(RbPolarsErr::from)?;
403
- Ok(s.into())
301
+ pub fn floor(rb: &Ruby, self_: &Self) -> RbResult<Self> {
302
+ rb.enter_polars_series(|| self_.series.read().floor())
404
303
  }
405
304
 
406
- pub fn shrink_to_fit(&self) {
407
- self.series.borrow_mut().shrink_to_fit();
305
+ pub fn shrink_to_fit(rb: &Ruby, self_: &Self) -> RbResult<()> {
306
+ rb.enter_polars_ok(|| self_.series.write().shrink_to_fit())
408
307
  }
409
308
 
410
- pub fn dot(&self, other: &RbSeries) -> RbResult<f64> {
411
- let out = self
412
- .series
413
- .borrow()
414
- .dot(&other.series.borrow())
415
- .map_err(RbPolarsErr::from)?;
416
- Ok(out)
309
+ pub fn dot(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Value> {
310
+ let s = &*self_.series.read();
311
+ let o = &*other.series.read();
312
+ let lhs_dtype = s.dtype();
313
+ let rhs_dtype = o.dtype();
314
+
315
+ if !lhs_dtype.is_primitive_numeric() {
316
+ return Err(RbPolarsErr::from(polars_err!(opq = dot, lhs_dtype)).into());
317
+ };
318
+ if !rhs_dtype.is_primitive_numeric() {
319
+ return Err(RbPolarsErr::from(polars_err!(opq = dot, rhs_dtype)).into());
320
+ }
321
+
322
+ let result: Value = if lhs_dtype.is_float() || rhs_dtype.is_float() {
323
+ rb.enter_polars(|| (s * o)?.sum::<f64>())?
324
+ .into_value_with(rb)
325
+ } else {
326
+ rb.enter_polars(|| (s * o)?.sum::<i64>())?
327
+ .into_value_with(rb)
328
+ };
329
+
330
+ Ok(result)
417
331
  }
418
332
 
419
- pub fn skew(&self, bias: bool) -> RbResult<Option<f64>> {
420
- let out = self.series.borrow().skew(bias).map_err(RbPolarsErr::from)?;
421
- Ok(out)
333
+ pub fn skew(rb: &Ruby, self_: &Self, bias: bool) -> RbResult<Option<f64>> {
334
+ rb.enter_polars(|| self_.series.read().skew(bias))
422
335
  }
423
336
 
424
- pub fn kurtosis(&self, fisher: bool, bias: bool) -> RbResult<Option<f64>> {
425
- let out = self
426
- .series
427
- .borrow()
428
- .kurtosis(fisher, bias)
429
- .map_err(RbPolarsErr::from)?;
430
- Ok(out)
337
+ pub fn kurtosis(rb: &Ruby, self_: &Self, fisher: bool, bias: bool) -> RbResult<Option<f64>> {
338
+ rb.enter_polars(|| self_.series.read().kurtosis(fisher, bias))
431
339
  }
432
340
 
433
- pub fn cast(&self, dtype: Wrap<DataType>, strict: bool) -> RbResult<Self> {
434
- let dtype = dtype.0;
435
- let out = if strict {
436
- self.series.borrow().strict_cast(&dtype)
341
+ pub fn cast(
342
+ rb: &Ruby,
343
+ self_: &Self,
344
+ dtype: Wrap<DataType>,
345
+ strict: bool,
346
+ wrap_numerical: bool,
347
+ ) -> RbResult<Self> {
348
+ let options = if wrap_numerical {
349
+ CastOptions::Overflowing
350
+ } else if strict {
351
+ CastOptions::Strict
437
352
  } else {
438
- self.series.borrow().cast(&dtype)
353
+ CastOptions::NonStrict
439
354
  };
440
- let out = out.map_err(RbPolarsErr::from)?;
441
- Ok(out.into())
355
+ rb.enter_polars_series(|| self_.series.read().cast_with_options(&dtype.0, options))
442
356
  }
443
357
 
444
- pub fn get_chunks(ruby: &Ruby, rb_self: &Self) -> RbResult<RArray> {
445
- ruby.ary_try_from_iter(
446
- flatten_series(&rb_self.series.borrow())
447
- .into_iter()
448
- .map(|s| rb_modules::pl_utils().funcall::<_, _, Value>("wrap_s", (Self::new(s),))),
449
- )
358
+ pub fn get_chunks(&self) -> RbResult<RArray> {
359
+ Ruby::attach(|rb| {
360
+ rb.ary_try_from_iter(flatten_series(&self.series.read()).into_iter().map(|s| {
361
+ rb_modules::pl_utils(rb).funcall::<_, _, Value>("wrap_s", (Self::new(s),))
362
+ }))
363
+ })
450
364
  }
451
365
 
452
- pub fn is_sorted(&self, descending: bool, nulls_last: bool) -> RbResult<bool> {
366
+ pub fn is_sorted(
367
+ rb: &Ruby,
368
+ self_: &Self,
369
+ descending: bool,
370
+ nulls_last: bool,
371
+ ) -> RbResult<bool> {
453
372
  let options = SortOptions {
454
373
  descending,
455
374
  nulls_last,
@@ -457,30 +376,85 @@ impl RbSeries {
457
376
  maintain_order: false,
458
377
  limit: None,
459
378
  };
460
- Ok(self
461
- .series
462
- .borrow()
463
- .is_sorted(options)
464
- .map_err(RbPolarsErr::from)?)
379
+ rb.enter_polars(|| self_.series.read().is_sorted(options))
465
380
  }
466
381
 
467
382
  pub fn clear(&self) -> Self {
468
- self.series.borrow().clear().into()
383
+ self.series.read().clear().into()
469
384
  }
470
385
 
471
- pub fn time_unit(&self) -> Option<String> {
472
- if let DataType::Datetime(tu, _) | DataType::Duration(tu) = self.series.borrow().dtype() {
473
- Some(
474
- match tu {
475
- TimeUnit::Nanoseconds => "ns",
476
- TimeUnit::Microseconds => "us",
477
- TimeUnit::Milliseconds => "ms",
478
- }
479
- .to_string(),
480
- )
481
- } else {
482
- None
483
- }
386
+ pub fn head(rb: &Ruby, self_: &Self, n: usize) -> RbResult<Self> {
387
+ rb.enter_polars_series(|| Ok(self_.series.read().head(Some(n))))
388
+ }
389
+
390
+ pub fn tail(rb: &Ruby, self_: &Self, n: usize) -> RbResult<Self> {
391
+ rb.enter_polars_series(|| Ok(self_.series.read().tail(Some(n))))
392
+ }
393
+
394
+ pub fn value_counts(
395
+ rb: &Ruby,
396
+ self_: &Self,
397
+ sort: bool,
398
+ parallel: bool,
399
+ name: String,
400
+ normalize: bool,
401
+ ) -> RbResult<RbDataFrame> {
402
+ rb.enter_polars_df(|| {
403
+ self_
404
+ .series
405
+ .read()
406
+ .value_counts(sort, parallel, name.into(), normalize)
407
+ })
408
+ }
409
+
410
+ pub fn slice(&self, offset: i64, length: Option<usize>) -> Self {
411
+ let s = self.series.read();
412
+ let length = length.unwrap_or_else(|| s.len());
413
+ s.slice(offset, length).into()
414
+ }
415
+
416
+ pub fn not_(rb: &Ruby, self_: &Self) -> RbResult<Self> {
417
+ rb.enter_polars_series(|| polars_ops::series::negate_bitwise(&self_.series.read()))
418
+ }
419
+
420
+ pub fn shrink_dtype(rb: &Ruby, self_: &Self) -> RbResult<Self> {
421
+ rb.enter_polars(|| {
422
+ self_
423
+ .series
424
+ .read()
425
+ .shrink_type()
426
+ .map(Into::into)
427
+ .map_err(RbPolarsErr::from)
428
+ .map_err(RbErr::from)
429
+ })
430
+ }
431
+
432
+ pub fn str_to_decimal_infer(
433
+ rb: &Ruby,
434
+ self_: &Self,
435
+ inference_length: usize,
436
+ ) -> RbResult<Self> {
437
+ rb.enter_polars_series(|| {
438
+ let s = self_.series.read();
439
+ let ca = s.str()?;
440
+ ca.to_decimal_infer(inference_length)
441
+ })
442
+ }
443
+
444
+ pub fn str_json_decode(
445
+ rb: &Ruby,
446
+ self_: &Self,
447
+ infer_schema_length: Option<usize>,
448
+ ) -> RbResult<Self> {
449
+ rb.enter_polars(|| {
450
+ let lock = self_.series.read();
451
+ lock.str()?
452
+ .json_decode(None, infer_schema_length)
453
+ .map(|s| s.with_name(lock.name().clone()))
454
+ })
455
+ .map(Into::into)
456
+ .map_err(RbPolarsErr::from)
457
+ .map_err(RbErr::from)
484
458
  }
485
459
  }
486
460
 
@@ -491,7 +465,7 @@ macro_rules! impl_set_with_mask {
491
465
  filter: &RbSeries,
492
466
  value: Option<$native>,
493
467
  ) -> PolarsResult<Series> {
494
- let binding = filter.series.borrow();
468
+ let binding = filter.series.read();
495
469
  let mask = binding.bool()?;
496
470
  let ca = series.$cast()?;
497
471
  let new = ca.set(mask, value)?;
@@ -499,10 +473,13 @@ macro_rules! impl_set_with_mask {
499
473
  }
500
474
 
501
475
  impl RbSeries {
502
- pub fn $name(&self, filter: &RbSeries, value: Option<$native>) -> RbResult<Self> {
503
- let series =
504
- $name(&self.series.borrow(), filter, value).map_err(RbPolarsErr::from)?;
505
- Ok(Self::new(series))
476
+ pub fn $name(
477
+ rb: &Ruby,
478
+ self_: &Self,
479
+ filter: &RbSeries,
480
+ value: Option<$native>,
481
+ ) -> RbResult<Self> {
482
+ rb.enter_polars_series(|| $name(&self_.series.read(), filter, value))
506
483
  }
507
484
  }
508
485
  };
@@ -520,15 +497,3 @@ impl_set_with_mask!(set_with_mask_i16, i16, i16, Int16);
520
497
  impl_set_with_mask!(set_with_mask_i32, i32, i32, Int32);
521
498
  impl_set_with_mask!(set_with_mask_i64, i64, i64, Int64);
522
499
  impl_set_with_mask!(set_with_mask_bool, bool, bool, Boolean);
523
-
524
- impl RbSeries {
525
- pub fn extend_constant(&self, value: Wrap<AnyValue>, n: usize) -> RbResult<Self> {
526
- Ok(self
527
- .series
528
- .borrow()
529
- .clone()
530
- .extend_constant(value.0, n)
531
- .map_err(RbPolarsErr::from)?
532
- .into())
533
- }
534
- }