polars-df 0.15.0 → 0.26.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 (206) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +274 -0
  3. data/Cargo.lock +1465 -867
  4. data/Cargo.toml +3 -0
  5. data/LICENSE.txt +2 -2
  6. data/README.md +87 -37
  7. data/ext/polars/Cargo.toml +47 -16
  8. data/ext/polars/src/c_api/allocator.rs +7 -0
  9. data/ext/polars/src/c_api/mod.rs +1 -0
  10. data/ext/polars/src/catalog/mod.rs +1 -0
  11. data/ext/polars/src/catalog/unity.rs +470 -0
  12. data/ext/polars/src/conversion/any_value.rs +99 -84
  13. data/ext/polars/src/conversion/categorical.rs +30 -0
  14. data/ext/polars/src/conversion/chunked_array.rs +71 -62
  15. data/ext/polars/src/conversion/datetime.rs +63 -0
  16. data/ext/polars/src/conversion/mod.rs +796 -312
  17. data/ext/polars/src/dataframe/construction.rs +6 -18
  18. data/ext/polars/src/dataframe/export.rs +30 -39
  19. data/ext/polars/src/dataframe/general.rs +294 -362
  20. data/ext/polars/src/dataframe/io.rs +33 -150
  21. data/ext/polars/src/dataframe/map.rs +175 -0
  22. data/ext/polars/src/dataframe/mod.rs +37 -5
  23. data/ext/polars/src/dataframe/serde.rs +23 -8
  24. data/ext/polars/src/error.rs +44 -7
  25. data/ext/polars/src/exceptions.rs +21 -8
  26. data/ext/polars/src/expr/array.rs +86 -22
  27. data/ext/polars/src/expr/binary.rs +50 -1
  28. data/ext/polars/src/expr/bitwise.rs +39 -0
  29. data/ext/polars/src/expr/categorical.rs +20 -0
  30. data/ext/polars/src/expr/datatype.rs +51 -0
  31. data/ext/polars/src/expr/datetime.rs +99 -41
  32. data/ext/polars/src/expr/extension.rs +12 -0
  33. data/ext/polars/src/expr/general.rs +252 -128
  34. data/ext/polars/src/expr/list.rs +56 -60
  35. data/ext/polars/src/expr/meta.rs +30 -35
  36. data/ext/polars/src/expr/mod.rs +28 -6
  37. data/ext/polars/src/expr/name.rs +29 -14
  38. data/ext/polars/src/expr/rolling.rs +111 -3
  39. data/ext/polars/src/expr/selector.rs +219 -0
  40. data/ext/polars/src/expr/serde.rs +28 -0
  41. data/ext/polars/src/expr/string.rs +118 -20
  42. data/ext/polars/src/expr/struct.rs +14 -1
  43. data/ext/polars/src/file.rs +194 -86
  44. data/ext/polars/src/functions/aggregation.rs +13 -12
  45. data/ext/polars/src/functions/business.rs +2 -3
  46. data/ext/polars/src/functions/eager.rs +3 -2
  47. data/ext/polars/src/functions/io.rs +90 -18
  48. data/ext/polars/src/functions/lazy.rs +267 -118
  49. data/ext/polars/src/functions/meta.rs +8 -7
  50. data/ext/polars/src/functions/misc.rs +1 -1
  51. data/ext/polars/src/functions/mod.rs +2 -1
  52. data/ext/polars/src/functions/range.rs +88 -31
  53. data/ext/polars/src/functions/strings.rs +6 -0
  54. data/ext/polars/src/functions/utils.rs +8 -0
  55. data/ext/polars/src/interop/arrow/mod.rs +52 -1
  56. data/ext/polars/src/interop/arrow/{to_ruby.rs → to_rb.rs} +37 -7
  57. data/ext/polars/src/interop/arrow/to_rust.rs +43 -0
  58. data/ext/polars/src/interop/numo/to_numo_df.rs +1 -1
  59. data/ext/polars/src/interop/numo/to_numo_series.rs +72 -50
  60. data/ext/polars/src/io/cloud_options.rs +107 -0
  61. data/ext/polars/src/io/mod.rs +4 -0
  62. data/ext/polars/src/io/scan_options.rs +113 -0
  63. data/ext/polars/src/io/sink_options.rs +46 -0
  64. data/ext/polars/src/io/sink_output.rs +21 -0
  65. data/ext/polars/src/lazyframe/exitable.rs +39 -0
  66. data/ext/polars/src/lazyframe/general.rs +846 -368
  67. data/ext/polars/src/lazyframe/mod.rs +58 -5
  68. data/ext/polars/src/lazyframe/optflags.rs +59 -0
  69. data/ext/polars/src/lazyframe/serde.rs +36 -4
  70. data/ext/polars/src/lazyframe/sink.rs +46 -0
  71. data/ext/polars/src/lazygroupby.rs +38 -9
  72. data/ext/polars/src/lib.rs +574 -165
  73. data/ext/polars/src/map/lazy.rs +44 -74
  74. data/ext/polars/src/map/mod.rs +18 -254
  75. data/ext/polars/src/map/series.rs +241 -1087
  76. data/ext/polars/src/on_startup.rs +192 -9
  77. data/ext/polars/src/prelude.rs +1 -0
  78. data/ext/polars/src/rb_modules.rs +10 -57
  79. data/ext/polars/src/ruby/exceptions.rs +26 -0
  80. data/ext/polars/src/ruby/gvl.rs +104 -0
  81. data/ext/polars/src/ruby/lazy.rs +46 -0
  82. data/ext/polars/src/ruby/mod.rs +11 -0
  83. data/ext/polars/src/ruby/numo.rs +52 -0
  84. data/ext/polars/src/ruby/plan_callback.rs +198 -0
  85. data/ext/polars/src/ruby/rb_modules.rs +16 -0
  86. data/ext/polars/src/ruby/ruby_convert_registry.rs +51 -0
  87. data/ext/polars/src/ruby/ruby_function.rs +11 -0
  88. data/ext/polars/src/ruby/ruby_udf.rs +164 -0
  89. data/ext/polars/src/ruby/thread.rs +65 -0
  90. data/ext/polars/src/ruby/utils.rs +39 -0
  91. data/ext/polars/src/series/aggregation.rs +116 -91
  92. data/ext/polars/src/series/arithmetic.rs +16 -22
  93. data/ext/polars/src/series/comparison.rs +101 -222
  94. data/ext/polars/src/series/construction.rs +80 -70
  95. data/ext/polars/src/series/export.rs +98 -56
  96. data/ext/polars/src/series/general.rs +323 -440
  97. data/ext/polars/src/series/import.rs +22 -5
  98. data/ext/polars/src/series/map.rs +103 -0
  99. data/ext/polars/src/series/mod.rs +57 -15
  100. data/ext/polars/src/series/scatter.rs +139 -82
  101. data/ext/polars/src/sql.rs +16 -9
  102. data/ext/polars/src/testing/frame.rs +31 -0
  103. data/ext/polars/src/testing/mod.rs +5 -0
  104. data/ext/polars/src/testing/series.rs +31 -0
  105. data/ext/polars/src/timeout.rs +105 -0
  106. data/ext/polars/src/utils.rs +105 -4
  107. data/lib/polars/array_expr.rb +500 -22
  108. data/lib/polars/array_name_space.rb +384 -10
  109. data/lib/polars/batched_csv_reader.rb +48 -66
  110. data/lib/polars/binary_expr.rb +217 -0
  111. data/lib/polars/binary_name_space.rb +155 -1
  112. data/lib/polars/cat_expr.rb +224 -0
  113. data/lib/polars/cat_name_space.rb +132 -32
  114. data/lib/polars/catalog/unity/catalog_info.rb +20 -0
  115. data/lib/polars/catalog/unity/column_info.rb +31 -0
  116. data/lib/polars/catalog/unity/namespace_info.rb +21 -0
  117. data/lib/polars/catalog/unity/table_info.rb +50 -0
  118. data/lib/polars/catalog.rb +448 -0
  119. data/lib/polars/collect_batches.rb +22 -0
  120. data/lib/polars/config.rb +3 -3
  121. data/lib/polars/convert.rb +201 -36
  122. data/lib/polars/data_frame.rb +2851 -1017
  123. data/lib/polars/data_frame_plot.rb +173 -0
  124. data/lib/polars/data_type_expr.rb +52 -0
  125. data/lib/polars/data_type_group.rb +6 -0
  126. data/lib/polars/data_types.rb +118 -18
  127. data/lib/polars/date_time_expr.rb +426 -84
  128. data/lib/polars/date_time_name_space.rb +384 -111
  129. data/lib/polars/dynamic_group_by.rb +102 -10
  130. data/lib/polars/exceptions.rb +50 -5
  131. data/lib/polars/expr.rb +2159 -915
  132. data/lib/polars/extension_expr.rb +39 -0
  133. data/lib/polars/extension_name_space.rb +39 -0
  134. data/lib/polars/functions/aggregation/horizontal.rb +11 -6
  135. data/lib/polars/functions/aggregation/vertical.rb +2 -3
  136. data/lib/polars/functions/as_datatype.rb +290 -8
  137. data/lib/polars/functions/business.rb +95 -0
  138. data/lib/polars/functions/col.rb +6 -5
  139. data/lib/polars/functions/datatype.rb +62 -0
  140. data/lib/polars/functions/eager.rb +426 -24
  141. data/lib/polars/functions/escape_regex.rb +21 -0
  142. data/lib/polars/functions/lazy.rb +813 -195
  143. data/lib/polars/functions/lit.rb +21 -10
  144. data/lib/polars/functions/range/int_range.rb +74 -2
  145. data/lib/polars/functions/range/linear_space.rb +195 -0
  146. data/lib/polars/functions/range/time_range.rb +1 -1
  147. data/lib/polars/functions/repeat.rb +7 -12
  148. data/lib/polars/functions/whenthen.rb +2 -2
  149. data/lib/polars/group_by.rb +188 -58
  150. data/lib/polars/iceberg_dataset.rb +108 -0
  151. data/lib/polars/in_process_query.rb +37 -0
  152. data/lib/polars/io/cloud.rb +18 -0
  153. data/lib/polars/io/csv.rb +336 -128
  154. data/lib/polars/io/database.rb +19 -4
  155. data/lib/polars/io/delta.rb +134 -0
  156. data/lib/polars/io/iceberg.rb +34 -0
  157. data/lib/polars/io/ipc.rb +63 -63
  158. data/lib/polars/io/json.rb +16 -0
  159. data/lib/polars/io/lines.rb +172 -0
  160. data/lib/polars/io/ndjson.rb +176 -20
  161. data/lib/polars/io/parquet.rb +173 -95
  162. data/lib/polars/io/scan_options.rb +55 -0
  163. data/lib/polars/io/sink_options.rb +27 -0
  164. data/lib/polars/io/utils.rb +17 -0
  165. data/lib/polars/lazy_frame.rb +3017 -622
  166. data/lib/polars/lazy_group_by.rb +436 -2
  167. data/lib/polars/list_expr.rb +551 -59
  168. data/lib/polars/list_name_space.rb +465 -51
  169. data/lib/polars/meta_expr.rb +146 -24
  170. data/lib/polars/name_expr.rb +87 -2
  171. data/lib/polars/query_opt_flags.rb +264 -0
  172. data/lib/polars/rolling_group_by.rb +90 -5
  173. data/lib/polars/scan_cast_options.rb +86 -0
  174. data/lib/polars/schema.rb +128 -0
  175. data/lib/polars/selector.rb +245 -0
  176. data/lib/polars/selectors.rb +1048 -201
  177. data/lib/polars/series.rb +2522 -774
  178. data/lib/polars/series_plot.rb +72 -0
  179. data/lib/polars/slice.rb +1 -1
  180. data/lib/polars/sql_context.rb +13 -6
  181. data/lib/polars/string_cache.rb +19 -72
  182. data/lib/polars/string_expr.rb +561 -107
  183. data/lib/polars/string_name_space.rb +781 -109
  184. data/lib/polars/struct_expr.rb +139 -18
  185. data/lib/polars/struct_name_space.rb +19 -1
  186. data/lib/polars/testing.rb +24 -273
  187. data/lib/polars/utils/constants.rb +2 -0
  188. data/lib/polars/utils/construction/data_frame.rb +410 -0
  189. data/lib/polars/utils/construction/series.rb +350 -0
  190. data/lib/polars/utils/construction/utils.rb +9 -0
  191. data/lib/polars/utils/convert.rb +18 -8
  192. data/lib/polars/utils/deprecation.rb +11 -0
  193. data/lib/polars/utils/parse.rb +62 -9
  194. data/lib/polars/utils/reduce_balanced.rb +43 -0
  195. data/lib/polars/utils/serde.rb +22 -0
  196. data/lib/polars/utils/unstable.rb +19 -0
  197. data/lib/polars/utils/various.rb +86 -1
  198. data/lib/polars/utils.rb +63 -48
  199. data/lib/polars/version.rb +1 -1
  200. data/lib/polars.rb +85 -2
  201. metadata +80 -28
  202. data/ext/polars/src/allocator.rs +0 -13
  203. data/ext/polars/src/batched_csv.rs +0 -138
  204. data/ext/polars/src/functions/string_cache.rs +0 -25
  205. data/ext/polars/src/map/dataframe.rs +0 -338
  206. data/lib/polars/plot.rb +0 -109
@@ -1,23 +1,26 @@
1
- use magnus::{exception, Error, IntoValue, Value};
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;
5
+ use polars_core::utils::flatten::flatten_series;
4
6
 
5
- use crate::apply_method_all_arrow_series2;
6
7
  use crate::conversion::*;
7
- use crate::map::series::{call_lambda_and_extract, ApplyLambda};
8
- use crate::{RbDataFrame, RbPolarsErr, RbResult, RbSeries};
8
+ use crate::prelude::*;
9
+ use crate::ruby::exceptions::{RbIndexError, RbRuntimeError, RbValueError};
10
+ use crate::ruby::gvl::GvlExt;
11
+ use crate::ruby::plan_callback::PlanCallbackExt;
12
+ use crate::ruby::ruby_function::RubyObject;
13
+ use crate::ruby::utils::TryIntoValue;
14
+ use crate::utils::EnterPolarsExt;
15
+ use crate::{RbDataFrame, RbErr, RbPolarsErr, RbResult, RbSeries};
9
16
 
10
17
  impl RbSeries {
11
- pub fn struct_unnest(&self) -> RbResult<RbDataFrame> {
12
- let binding = self.series.borrow();
13
- let ca = binding.struct_().map_err(RbPolarsErr::from)?;
14
- let df: DataFrame = ca.clone().unnest();
15
- Ok(df.into())
18
+ pub fn struct_unnest(rb: &Ruby, self_: &Self) -> RbResult<RbDataFrame> {
19
+ rb.enter_polars_df(|| Ok(self_.series.read().struct_()?.clone().unnest()))
16
20
  }
17
21
 
18
- // TODO add to Ruby
19
22
  pub fn struct_fields(&self) -> RbResult<Vec<String>> {
20
- let binding = self.series.borrow();
23
+ let binding = self.series.read();
21
24
  let ca = binding.struct_().map_err(RbPolarsErr::from)?;
22
25
  Ok(ca
23
26
  .struct_fields()
@@ -27,45 +30,48 @@ impl RbSeries {
27
30
  }
28
31
 
29
32
  pub fn is_sorted_ascending_flag(&self) -> bool {
30
- matches!(self.series.borrow().is_sorted_flag(), IsSorted::Ascending)
33
+ matches!(self.series.read().is_sorted_flag(), IsSorted::Ascending)
31
34
  }
32
35
 
33
36
  pub fn is_sorted_descending_flag(&self) -> bool {
34
- matches!(self.series.borrow().is_sorted_flag(), IsSorted::Descending)
37
+ matches!(self.series.read().is_sorted_flag(), IsSorted::Descending)
35
38
  }
36
39
 
37
40
  pub fn can_fast_explode_flag(&self) -> bool {
38
- match self.series.borrow().list() {
41
+ match self.series.read().list() {
39
42
  Err(_) => false,
40
43
  Ok(list) => list._can_fast_explode(),
41
44
  }
42
45
  }
43
46
 
44
47
  pub fn cat_uses_lexical_ordering(&self) -> RbResult<bool> {
45
- let binding = self.series.borrow();
46
- let ca = binding.categorical().map_err(RbPolarsErr::from)?;
47
- Ok(ca.uses_lexical_ordering())
48
+ Ok(true)
48
49
  }
49
50
 
50
51
  pub fn cat_is_local(&self) -> RbResult<bool> {
51
- let binding = self.series.borrow();
52
- let ca = binding.categorical().map_err(RbPolarsErr::from)?;
53
- Ok(ca.get_rev_map().is_local())
52
+ Ok(false)
54
53
  }
55
54
 
56
55
  pub fn cat_to_local(&self) -> RbResult<Self> {
57
- let binding = self.series.borrow();
58
- let ca = binding.categorical().map_err(RbPolarsErr::from)?;
59
- Ok(ca.to_local().into_series().into())
56
+ Ok(self.clone())
60
57
  }
61
58
 
62
59
  pub fn estimated_size(&self) -> usize {
63
- self.series.borrow().estimated_size()
60
+ self.series.read().estimated_size()
61
+ }
62
+
63
+ pub fn reshape(rb: &Ruby, self_: &Self, dims: Vec<i64>) -> RbResult<Self> {
64
+ let dims = dims
65
+ .into_iter()
66
+ .map(ReshapeDimension::new)
67
+ .collect::<Vec<_>>();
68
+
69
+ rb.enter_polars_series(|| self_.series.read().reshape_array(&dims))
64
70
  }
65
71
 
66
72
  pub fn get_fmt(&self, index: usize, str_lengths: usize) -> String {
67
- let val = format!("{}", self.series.borrow().get(index).unwrap());
68
- if let DataType::String | DataType::Categorical(_, _) = self.series.borrow().dtype() {
73
+ let val = format!("{}", self.series.read().get(index).unwrap());
74
+ if let DataType::String | DataType::Categorical(_, _) = self.series.read().dtype() {
69
75
  let v_trunc = &val[..val
70
76
  .char_indices()
71
77
  .take(str_lengths)
@@ -75,80 +81,88 @@ impl RbSeries {
75
81
  if val == v_trunc {
76
82
  val
77
83
  } else {
78
- format!("{}…", v_trunc)
84
+ format!("{v_trunc}…")
79
85
  }
80
86
  } else {
81
87
  val
82
88
  }
83
89
  }
84
90
 
85
- pub fn rechunk(&self, in_place: bool) -> Option<Self> {
86
- let series = self.series.borrow_mut().rechunk();
91
+ pub fn rechunk(rb: &Ruby, self_: &Self, in_place: bool) -> RbResult<Option<Self>> {
92
+ let series = rb.enter_polars_ok(|| self_.series.read().rechunk())?;
87
93
  if in_place {
88
- *self.series.borrow_mut() = series;
89
- None
94
+ *self_.series.write() = series;
95
+ Ok(None)
90
96
  } else {
91
- Some(series.into())
97
+ Ok(Some(series.into()))
98
+ }
99
+ }
100
+
101
+ pub fn get_index(ruby: &Ruby, self_: &Self, index: usize) -> RbResult<Value> {
102
+ let binding = self_.series.read();
103
+ let av = match binding.get(index) {
104
+ Ok(v) => v,
105
+ Err(PolarsError::OutOfBounds(err)) => {
106
+ return Err(RbIndexError::new_err(err.to_string()));
107
+ }
108
+ Err(e) => return Err(RbPolarsErr::from(e).into()),
109
+ };
110
+
111
+ match av {
112
+ AnyValue::List(s) | AnyValue::Array(s, _) => {
113
+ let rbseries = RbSeries::new(s);
114
+ rb_modules::pl_utils(ruby).funcall("wrap_s", (rbseries,))
115
+ }
116
+ _ => Wrap(av).try_into_value_with(ruby),
92
117
  }
93
118
  }
94
119
 
95
- pub fn get_idx(&self, idx: usize) -> RbResult<Value> {
96
- Ok(Wrap(self.series.borrow().get(idx).map_err(RbPolarsErr::from)?).into_value())
120
+ pub fn get_index_signed(ruby: &Ruby, self_: &Self, index: isize) -> RbResult<Value> {
121
+ let index = if index < 0 {
122
+ match self_.len().checked_sub(index.unsigned_abs()) {
123
+ Some(v) => v,
124
+ None => {
125
+ return Err(RbIndexError::new_err(
126
+ polars_err!(oob = index, self_.len()).to_string(),
127
+ ));
128
+ }
129
+ }
130
+ } else {
131
+ usize::try_from(index).unwrap()
132
+ };
133
+ Self::get_index(ruby, self_, index)
97
134
  }
98
135
 
99
- pub fn bitand(&self, other: &RbSeries) -> RbResult<Self> {
100
- let out = self
101
- .series
102
- .borrow()
103
- .bitand(&other.series.borrow())
104
- .map_err(RbPolarsErr::from)?;
105
- Ok(out.into())
136
+ pub fn bitand(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
137
+ rb.enter_polars_series(|| &*self_.series.read() & &*other.series.read())
106
138
  }
107
139
 
108
- pub fn bitor(&self, other: &RbSeries) -> RbResult<Self> {
109
- let out = self
110
- .series
111
- .borrow()
112
- .bitor(&other.series.borrow())
113
- .map_err(RbPolarsErr::from)?;
114
- Ok(out.into())
140
+ pub fn bitor(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
141
+ rb.enter_polars_series(|| &*self_.series.read() | &*other.series.read())
115
142
  }
116
143
 
117
- pub fn bitxor(&self, other: &RbSeries) -> RbResult<Self> {
118
- let out = self
119
- .series
120
- .borrow()
121
- .bitxor(&other.series.borrow())
122
- .map_err(RbPolarsErr::from)?;
123
- Ok(out.into())
144
+ pub fn bitxor(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Self> {
145
+ rb.enter_polars_series(|| &*self_.series.read() ^ &*other.series.read())
124
146
  }
125
147
 
126
148
  pub fn chunk_lengths(&self) -> Vec<usize> {
127
- self.series.borrow().chunk_lengths().collect()
149
+ self.series.read().chunk_lengths().collect()
128
150
  }
129
151
 
130
152
  pub fn name(&self) -> String {
131
- self.series.borrow().name().to_string()
153
+ self.series.read().name().to_string()
132
154
  }
133
155
 
134
156
  pub fn rename(&self, name: String) {
135
- self.series.borrow_mut().rename(name.into());
157
+ self.series.write().rename(name.into());
136
158
  }
137
159
 
138
- pub fn dtype(&self) -> Value {
139
- Wrap(self.series.borrow().dtype().clone()).into_value()
140
- }
141
-
142
- pub fn inner_dtype(&self) -> Option<Value> {
143
- self.series
144
- .borrow()
145
- .dtype()
146
- .inner_dtype()
147
- .map(|dt| Wrap(dt.clone()).into_value())
160
+ pub fn dtype(rb: &Ruby, self_: &Self) -> RbResult<Value> {
161
+ Wrap(self_.series.read().dtype().clone()).try_into_value_with(rb)
148
162
  }
149
163
 
150
164
  pub fn set_sorted_flag(&self, descending: bool) -> Self {
151
- let mut out = self.series.borrow().clone();
165
+ let mut out = self.series.read().clone();
152
166
  if descending {
153
167
  out.set_sorted_flag(IsSorted::Descending);
154
168
  } else {
@@ -158,438 +172,316 @@ impl RbSeries {
158
172
  }
159
173
 
160
174
  pub fn n_chunks(&self) -> usize {
161
- self.series.borrow().n_chunks()
175
+ self.series.read().n_chunks()
162
176
  }
163
177
 
164
- pub fn append(&self, other: &RbSeries) -> RbResult<()> {
165
- let mut binding = self.series.borrow_mut();
166
- let res = binding.append(&other.series.borrow());
167
- if let Err(e) = res {
168
- Err(Error::new(exception::runtime_error(), e.to_string()))
169
- } else {
170
- Ok(())
171
- }
178
+ pub fn append(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<()> {
179
+ rb.enter_polars(|| {
180
+ // Prevent self-append deadlocks.
181
+ let other = other.series.read().clone();
182
+ let mut s = self_.series.write();
183
+ s.append(&other)?;
184
+ PolarsResult::Ok(())
185
+ })
172
186
  }
173
187
 
174
- pub fn extend(&self, other: &RbSeries) -> RbResult<()> {
175
- self.series
176
- .borrow_mut()
177
- .extend(&other.series.borrow())
178
- .map_err(RbPolarsErr::from)?;
179
- Ok(())
188
+ pub fn extend(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<()> {
189
+ rb.enter_polars(|| {
190
+ // Prevent self-extend deadlocks.
191
+ let other = other.series.read().clone();
192
+ let mut s = self_.series.write();
193
+ s.extend(&other)?;
194
+ PolarsResult::Ok(())
195
+ })
180
196
  }
181
197
 
182
- pub fn new_from_index(&self, index: usize, length: usize) -> RbResult<Self> {
183
- if index >= self.series.borrow().len() {
184
- Err(Error::new(exception::arg_error(), "index is out of bounds"))
198
+ pub fn new_from_index(rb: &Ruby, self_: &Self, index: usize, length: usize) -> RbResult<Self> {
199
+ let s = self_.series.read();
200
+ if index >= s.len() {
201
+ Err(RbValueError::new_err("index is out of bounds"))
185
202
  } else {
186
- Ok(self.series.borrow().new_from_index(index, length).into())
203
+ rb.enter_polars_series(|| Ok(s.new_from_index(index, length)))
187
204
  }
188
205
  }
189
206
 
190
- pub fn filter(&self, filter: &RbSeries) -> RbResult<Self> {
191
- let filter_series = &filter.series.borrow();
207
+ pub fn filter(rb: &Ruby, self_: &Self, filter: &RbSeries) -> RbResult<Self> {
208
+ let filter_series = &filter.series.read();
192
209
  if let Ok(ca) = filter_series.bool() {
193
- let series = self.series.borrow().filter(ca).unwrap();
194
- Ok(series.into())
210
+ rb.enter_polars_series(|| self_.series.read().filter(ca))
195
211
  } else {
196
- Err(Error::new(
197
- exception::runtime_error(),
198
- "Expected a boolean mask".to_string(),
199
- ))
212
+ Err(RbRuntimeError::new_err("Expected a boolean mask"))
200
213
  }
201
214
  }
202
215
 
203
- pub fn sort(&self, descending: bool, nulls_last: bool, multithreaded: bool) -> RbResult<Self> {
204
- Ok(self
205
- .series
206
- .borrow_mut()
207
- .sort(
216
+ pub fn sort(
217
+ rb: &Ruby,
218
+ self_: &Self,
219
+ descending: bool,
220
+ nulls_last: bool,
221
+ multithreaded: bool,
222
+ ) -> RbResult<Self> {
223
+ rb.enter_polars_series(|| {
224
+ self_.series.read().sort(
208
225
  SortOptions::default()
209
226
  .with_order_descending(descending)
210
227
  .with_nulls_last(nulls_last)
211
228
  .with_multithreaded(multithreaded),
212
229
  )
213
- .map_err(RbPolarsErr::from)?
214
- .into())
215
- }
216
-
217
- pub fn value_counts(
218
- &self,
219
- sort: bool,
220
- parallel: bool,
221
- name: String,
222
- normalize: bool,
223
- ) -> RbResult<RbDataFrame> {
224
- let out = self
225
- .series
226
- .borrow()
227
- .value_counts(sort, parallel, name.into(), normalize)
228
- .map_err(RbPolarsErr::from)?;
229
- Ok(out.into())
230
- }
231
-
232
- pub fn slice(&self, offset: i64, length: Option<usize>) -> Self {
233
- let length = length.unwrap_or_else(|| self.series.borrow().len());
234
- self.series.borrow().slice(offset, length).into()
230
+ })
235
231
  }
236
232
 
237
- pub fn take_with_series(&self, indices: &RbSeries) -> RbResult<Self> {
238
- let binding = indices.series.borrow();
239
- let idx = binding.idx().map_err(RbPolarsErr::from)?;
240
- let take = self.series.borrow().take(idx).map_err(RbPolarsErr::from)?;
241
- Ok(RbSeries::new(take))
233
+ pub fn gather_with_series(rb: &Ruby, self_: &Self, indices: &RbSeries) -> RbResult<Self> {
234
+ rb.enter_polars_series(|| self_.series.read().take(indices.series.read().idx()?))
242
235
  }
243
236
 
244
237
  pub fn null_count(&self) -> RbResult<usize> {
245
- Ok(self.series.borrow().null_count())
238
+ Ok(self.series.read().null_count())
246
239
  }
247
240
 
248
241
  pub fn has_nulls(&self) -> bool {
249
- self.series.borrow().has_nulls()
250
- }
251
-
252
- pub fn sample_n(
253
- &self,
254
- n: usize,
255
- with_replacement: bool,
256
- shuffle: bool,
257
- seed: Option<u64>,
258
- ) -> RbResult<Self> {
259
- let s = self
260
- .series
261
- .borrow()
262
- .sample_n(n, with_replacement, shuffle, seed)
263
- .map_err(RbPolarsErr::from)?;
264
- Ok(s.into())
265
- }
266
-
267
- pub fn sample_frac(
268
- &self,
269
- frac: f64,
270
- with_replacement: bool,
271
- shuffle: bool,
272
- seed: Option<u64>,
273
- ) -> RbResult<Self> {
274
- let s = self
275
- .series
276
- .borrow()
277
- .sample_frac(frac, with_replacement, shuffle, seed)
278
- .map_err(RbPolarsErr::from)?;
279
- Ok(s.into())
242
+ self.series.read().has_nulls()
280
243
  }
281
244
 
282
245
  pub fn equals(
283
- &self,
246
+ rb: &Ruby,
247
+ self_: &Self,
284
248
  other: &RbSeries,
285
249
  check_dtypes: bool,
286
250
  check_names: bool,
287
251
  null_equal: bool,
288
- ) -> bool {
289
- if check_dtypes && (self.series.borrow().dtype() != other.series.borrow().dtype()) {
290
- return false;
252
+ ) -> RbResult<bool> {
253
+ let s = self_.series.read();
254
+ let o = other.series.read();
255
+ if check_dtypes && (s.dtype() != o.dtype()) {
256
+ return Ok(false);
291
257
  }
292
- if check_names && (self.series.borrow().name() != other.series.borrow().name()) {
293
- return false;
258
+ if check_names && (s.name() != o.name()) {
259
+ return Ok(false);
294
260
  }
295
261
  if null_equal {
296
- self.series.borrow().equals_missing(&other.series.borrow())
262
+ rb.enter_polars_ok(|| s.equals_missing(&o))
297
263
  } else {
298
- self.series.borrow().equals(&other.series.borrow())
264
+ rb.enter_polars_ok(|| s.equals(&o))
299
265
  }
300
266
  }
301
267
 
302
- pub fn not(&self) -> RbResult<Self> {
303
- let binding = self.series.borrow();
304
- let bool = binding.bool().map_err(RbPolarsErr::from)?;
305
- Ok((!bool).into_series().into())
306
- }
307
-
308
- pub fn to_s(&self) -> String {
309
- format!("{}", self.series.borrow())
268
+ pub fn as_str(&self) -> String {
269
+ format!("{:?}", self.series.read())
310
270
  }
311
271
 
312
272
  pub fn len(&self) -> usize {
313
- self.series.borrow().len()
273
+ self.series.read().len()
314
274
  }
315
275
 
316
276
  pub fn clone(&self) -> Self {
317
- RbSeries::new(self.series.borrow().clone())
277
+ Clone::clone(self)
318
278
  }
319
279
 
320
- pub fn apply_lambda(
321
- &self,
322
- lambda: Value,
323
- output_type: Option<Wrap<DataType>>,
324
- skip_nulls: bool,
325
- ) -> RbResult<Self> {
326
- let series = &self.series.borrow();
327
-
328
- let output_type = output_type.map(|dt| dt.0);
329
-
330
- macro_rules! dispatch_apply {
331
- ($self:expr, $method:ident, $($args:expr),*) => {
332
- if matches!($self.dtype(), DataType::Object(_, _)) {
333
- // let ca = $self.0.unpack::<ObjectType<ObjectValue>>().unwrap();
334
- // ca.$method($($args),*)
335
- todo!()
336
- } else {
337
- apply_method_all_arrow_series2!(
338
- $self,
339
- $method,
340
- $($args),*
341
- )
342
- }
280
+ pub fn zip_with(rb: &Ruby, self_: &Self, mask: &RbSeries, other: &RbSeries) -> RbResult<Self> {
281
+ let ms = mask.series.read();
282
+ let mask = ms.bool().map_err(RbPolarsErr::from)?;
283
+ rb.enter_polars_series(|| self_.series.read().zip_with(mask, &other.series.read()))
284
+ }
343
285
 
344
- }
286
+ pub fn to_dummies(
287
+ rb: &Ruby,
288
+ self_: &Self,
289
+ separator: Option<String>,
290
+ drop_first: bool,
291
+ drop_nulls: bool,
292
+ ) -> RbResult<RbDataFrame> {
293
+ rb.enter_polars_df(|| {
294
+ self_
295
+ .series
296
+ .read()
297
+ .to_dummies(separator.as_deref(), drop_first, drop_nulls)
298
+ })
299
+ }
345
300
 
346
- }
301
+ pub fn n_unique(rb: &Ruby, self_: &Self) -> RbResult<usize> {
302
+ rb.enter_polars(|| self_.series.read().n_unique())
303
+ }
347
304
 
348
- if matches!(
349
- series.dtype(),
350
- DataType::Datetime(_, _)
351
- | DataType::Date
352
- | DataType::Duration(_)
353
- | DataType::Categorical(_, _)
354
- | DataType::Time
355
- ) || !skip_nulls
356
- {
357
- let mut avs = Vec::with_capacity(series.len());
358
- let iter = series.iter().map(|av| {
359
- let input = Wrap(av);
360
- call_lambda_and_extract::<_, Wrap<AnyValue>>(lambda, input)
361
- .unwrap()
362
- .0
363
- });
364
- avs.extend(iter);
365
- return Ok(Series::new(self.name().into(), &avs).into());
366
- }
305
+ pub fn floor(rb: &Ruby, self_: &Self) -> RbResult<Self> {
306
+ rb.enter_polars_series(|| self_.series.read().floor())
307
+ }
367
308
 
368
- let out = match output_type {
369
- Some(DataType::Int8) => {
370
- let ca: Int8Chunked = dispatch_apply!(
371
- series,
372
- apply_lambda_with_primitive_out_type,
373
- lambda,
374
- 0,
375
- None
376
- )?;
377
- ca.into_series()
378
- }
379
- Some(DataType::Int16) => {
380
- let ca: Int16Chunked = dispatch_apply!(
381
- series,
382
- apply_lambda_with_primitive_out_type,
383
- lambda,
384
- 0,
385
- None
386
- )?;
387
- ca.into_series()
388
- }
389
- Some(DataType::Int32) => {
390
- let ca: Int32Chunked = dispatch_apply!(
391
- series,
392
- apply_lambda_with_primitive_out_type,
393
- lambda,
394
- 0,
395
- None
396
- )?;
397
- ca.into_series()
398
- }
399
- Some(DataType::Int64) => {
400
- let ca: Int64Chunked = dispatch_apply!(
401
- series,
402
- apply_lambda_with_primitive_out_type,
403
- lambda,
404
- 0,
405
- None
406
- )?;
407
- ca.into_series()
408
- }
409
- Some(DataType::UInt8) => {
410
- let ca: UInt8Chunked = dispatch_apply!(
411
- series,
412
- apply_lambda_with_primitive_out_type,
413
- lambda,
414
- 0,
415
- None
416
- )?;
417
- ca.into_series()
418
- }
419
- Some(DataType::UInt16) => {
420
- let ca: UInt16Chunked = dispatch_apply!(
421
- series,
422
- apply_lambda_with_primitive_out_type,
423
- lambda,
424
- 0,
425
- None
426
- )?;
427
- ca.into_series()
428
- }
429
- Some(DataType::UInt32) => {
430
- let ca: UInt32Chunked = dispatch_apply!(
431
- series,
432
- apply_lambda_with_primitive_out_type,
433
- lambda,
434
- 0,
435
- None
436
- )?;
437
- ca.into_series()
438
- }
439
- Some(DataType::UInt64) => {
440
- let ca: UInt64Chunked = dispatch_apply!(
441
- series,
442
- apply_lambda_with_primitive_out_type,
443
- lambda,
444
- 0,
445
- None
446
- )?;
447
- ca.into_series()
448
- }
449
- Some(DataType::Float32) => {
450
- let ca: Float32Chunked = dispatch_apply!(
451
- series,
452
- apply_lambda_with_primitive_out_type,
453
- lambda,
454
- 0,
455
- None
456
- )?;
457
- ca.into_series()
458
- }
459
- Some(DataType::Float64) => {
460
- let ca: Float64Chunked = dispatch_apply!(
461
- series,
462
- apply_lambda_with_primitive_out_type,
463
- lambda,
464
- 0,
465
- None
466
- )?;
467
- ca.into_series()
468
- }
469
- Some(DataType::Boolean) => {
470
- let ca: BooleanChunked =
471
- dispatch_apply!(series, apply_lambda_with_bool_out_type, lambda, 0, None)?;
472
- ca.into_series()
473
- }
474
- Some(DataType::Date) => {
475
- let ca: Int32Chunked = dispatch_apply!(
476
- series,
477
- apply_lambda_with_primitive_out_type,
478
- lambda,
479
- 0,
480
- None
481
- )?;
482
- ca.into_date().into_series()
483
- }
484
- Some(DataType::Datetime(tu, tz)) => {
485
- let ca: Int64Chunked = dispatch_apply!(
486
- series,
487
- apply_lambda_with_primitive_out_type,
488
- lambda,
489
- 0,
490
- None
491
- )?;
492
- ca.into_datetime(tu, tz).into_series()
493
- }
494
- Some(DataType::String) => {
495
- let ca = dispatch_apply!(series, apply_lambda_with_utf8_out_type, lambda, 0, None)?;
309
+ pub fn shrink_to_fit(rb: &Ruby, self_: &Self) -> RbResult<()> {
310
+ rb.enter_polars_ok(|| self_.series.write().shrink_to_fit())
311
+ }
496
312
 
497
- ca.into_series()
498
- }
499
- Some(DataType::Object(_, _)) => {
500
- let ca =
501
- dispatch_apply!(series, apply_lambda_with_object_out_type, lambda, 0, None)?;
502
- ca.into_series()
503
- }
504
- None => return dispatch_apply!(series, apply_lambda_unknown, lambda),
313
+ pub fn dot(rb: &Ruby, self_: &Self, other: &RbSeries) -> RbResult<Value> {
314
+ let s = &*self_.series.read();
315
+ let o = &*other.series.read();
316
+ let lhs_dtype = s.dtype();
317
+ let rhs_dtype = o.dtype();
318
+
319
+ if !lhs_dtype.is_primitive_numeric() {
320
+ return Err(RbPolarsErr::from(polars_err!(opq = dot, lhs_dtype)).into());
321
+ };
322
+ if !rhs_dtype.is_primitive_numeric() {
323
+ return Err(RbPolarsErr::from(polars_err!(opq = dot, rhs_dtype)).into());
324
+ }
505
325
 
506
- _ => return dispatch_apply!(series, apply_lambda_unknown, lambda),
326
+ let result: Value = if lhs_dtype.is_float() || rhs_dtype.is_float() {
327
+ rb.enter_polars(|| (s * o)?.sum::<f64>())?
328
+ .into_value_with(rb)
329
+ } else {
330
+ rb.enter_polars(|| (s * o)?.sum::<i64>())?
331
+ .into_value_with(rb)
507
332
  };
508
333
 
509
- Ok(RbSeries::new(out))
334
+ Ok(result)
510
335
  }
511
336
 
512
- pub fn zip_with(&self, mask: &RbSeries, other: &RbSeries) -> RbResult<Self> {
513
- let binding = mask.series.borrow();
514
- let mask = binding.bool().map_err(RbPolarsErr::from)?;
515
- let s = self
516
- .series
517
- .borrow()
518
- .zip_with(mask, &other.series.borrow())
519
- .map_err(RbPolarsErr::from)?;
520
- Ok(RbSeries::new(s))
337
+ pub fn skew(rb: &Ruby, self_: &Self, bias: bool) -> RbResult<Option<f64>> {
338
+ rb.enter_polars(|| self_.series.read().skew(bias))
521
339
  }
522
340
 
523
- pub fn to_dummies(&self, sep: Option<String>, drop_first: bool) -> RbResult<RbDataFrame> {
524
- let df = self
525
- .series
526
- .borrow()
527
- .to_dummies(sep.as_deref(), drop_first)
528
- .map_err(RbPolarsErr::from)?;
529
- Ok(df.into())
341
+ pub fn kurtosis(rb: &Ruby, self_: &Self, fisher: bool, bias: bool) -> RbResult<Option<f64>> {
342
+ rb.enter_polars(|| self_.series.read().kurtosis(fisher, bias))
530
343
  }
531
344
 
532
- pub fn n_unique(&self) -> RbResult<usize> {
533
- let n = self.series.borrow().n_unique().map_err(RbPolarsErr::from)?;
534
- Ok(n)
345
+ pub fn cast(
346
+ rb: &Ruby,
347
+ self_: &Self,
348
+ dtype: Wrap<DataType>,
349
+ strict: bool,
350
+ wrap_numerical: bool,
351
+ ) -> RbResult<Self> {
352
+ let options = if wrap_numerical {
353
+ CastOptions::Overflowing
354
+ } else if strict {
355
+ CastOptions::Strict
356
+ } else {
357
+ CastOptions::NonStrict
358
+ };
359
+ rb.enter_polars_series(|| self_.series.read().cast_with_options(&dtype.0, options))
360
+ }
361
+
362
+ pub fn get_chunks(&self) -> RbResult<RArray> {
363
+ Ruby::attach(|rb| {
364
+ rb.ary_try_from_iter(flatten_series(&self.series.read()).into_iter().map(|s| {
365
+ rb_modules::pl_utils(rb).funcall::<_, _, Value>("wrap_s", (Self::new(s),))
366
+ }))
367
+ })
368
+ }
369
+
370
+ pub fn is_sorted(
371
+ rb: &Ruby,
372
+ self_: &Self,
373
+ descending: bool,
374
+ nulls_last: bool,
375
+ ) -> RbResult<bool> {
376
+ let options = SortOptions {
377
+ descending,
378
+ nulls_last,
379
+ multithreaded: true,
380
+ maintain_order: false,
381
+ limit: None,
382
+ };
383
+ rb.enter_polars(|| self_.series.read().is_sorted(options))
535
384
  }
536
385
 
537
- pub fn floor(&self) -> RbResult<Self> {
538
- let s = self.series.borrow().floor().map_err(RbPolarsErr::from)?;
539
- Ok(s.into())
386
+ pub fn clear(&self) -> Self {
387
+ self.series.read().clear().into()
540
388
  }
541
389
 
542
- pub fn shrink_to_fit(&self) {
543
- self.series.borrow_mut().shrink_to_fit();
390
+ pub fn head(rb: &Ruby, self_: &Self, n: usize) -> RbResult<Self> {
391
+ rb.enter_polars_series(|| Ok(self_.series.read().head(Some(n))))
544
392
  }
545
393
 
546
- pub fn dot(&self, other: &RbSeries) -> RbResult<f64> {
547
- let out = self
548
- .series
549
- .borrow()
550
- .dot(&other.series.borrow())
551
- .map_err(RbPolarsErr::from)?;
552
- Ok(out)
394
+ pub fn tail(rb: &Ruby, self_: &Self, n: usize) -> RbResult<Self> {
395
+ rb.enter_polars_series(|| Ok(self_.series.read().tail(Some(n))))
553
396
  }
554
397
 
555
- pub fn skew(&self, bias: bool) -> RbResult<Option<f64>> {
556
- let out = self.series.borrow().skew(bias).map_err(RbPolarsErr::from)?;
557
- Ok(out)
398
+ pub fn value_counts(
399
+ rb: &Ruby,
400
+ self_: &Self,
401
+ sort: bool,
402
+ parallel: bool,
403
+ name: String,
404
+ normalize: bool,
405
+ ) -> RbResult<RbDataFrame> {
406
+ rb.enter_polars_df(|| {
407
+ self_
408
+ .series
409
+ .read()
410
+ .value_counts(sort, parallel, name.into(), normalize)
411
+ })
558
412
  }
559
413
 
560
- pub fn kurtosis(&self, fisher: bool, bias: bool) -> RbResult<Option<f64>> {
561
- let out = self
562
- .series
563
- .borrow()
564
- .kurtosis(fisher, bias)
565
- .map_err(RbPolarsErr::from)?;
566
- Ok(out)
414
+ pub fn slice(&self, offset: i64, length: Option<usize>) -> Self {
415
+ let s = self.series.read();
416
+ let length = length.unwrap_or_else(|| s.len());
417
+ s.slice(offset, length).into()
567
418
  }
568
419
 
569
- pub fn cast(&self, dtype: Wrap<DataType>, strict: bool) -> RbResult<Self> {
570
- let dtype = dtype.0;
571
- let out = if strict {
572
- self.series.borrow().strict_cast(&dtype)
573
- } else {
574
- self.series.borrow().cast(&dtype)
575
- };
576
- let out = out.map_err(RbPolarsErr::from)?;
577
- Ok(out.into())
420
+ pub fn not_(rb: &Ruby, self_: &Self) -> RbResult<Self> {
421
+ rb.enter_polars_series(|| polars_ops::series::negate_bitwise(&self_.series.read()))
578
422
  }
579
423
 
580
- pub fn time_unit(&self) -> Option<String> {
581
- if let DataType::Datetime(tu, _) | DataType::Duration(tu) = self.series.borrow().dtype() {
582
- Some(
583
- match tu {
584
- TimeUnit::Nanoseconds => "ns",
585
- TimeUnit::Microseconds => "us",
586
- TimeUnit::Milliseconds => "ms",
587
- }
588
- .to_string(),
589
- )
590
- } else {
591
- None
592
- }
424
+ pub fn shrink_dtype(rb: &Ruby, self_: &Self) -> RbResult<Self> {
425
+ rb.enter_polars(|| self_.series.read().shrink_type().map(Into::into))
426
+ .map_err(RbPolarsErr::from)
427
+ .map_err(RbErr::from)
428
+ }
429
+
430
+ pub fn str_to_decimal_infer(
431
+ rb: &Ruby,
432
+ self_: &Self,
433
+ inference_length: usize,
434
+ ) -> RbResult<Self> {
435
+ rb.enter_polars_series(|| {
436
+ let s = self_.series.read();
437
+ let ca = s.str()?;
438
+ ca.to_decimal_infer(inference_length)
439
+ })
440
+ }
441
+
442
+ pub fn list_to_struct(
443
+ rb: &Ruby,
444
+ self_: &Self,
445
+ width_strat: Wrap<ListToStructWidthStrategy>,
446
+ name_gen: Option<Value>,
447
+ ) -> RbResult<Self> {
448
+ let name_gen = name_gen.map(RubyObject::from);
449
+ // ensure new_ruby is called with GVL
450
+ let get_index_name = name_gen.map(PlanCallback::<usize, String>::new_ruby);
451
+ rb.enter_polars(|| {
452
+ let get_index_name = get_index_name.map(|f| {
453
+ NameGenerator(Arc::new(move |i| f.call(i).map(PlSmallStr::from)) as Arc<_>)
454
+ });
455
+ self_
456
+ .series
457
+ .read()
458
+ .list()?
459
+ .to_struct(&ListToStructArgs::InferWidth {
460
+ infer_field_strategy: width_strat.0,
461
+ get_index_name,
462
+ max_fields: None,
463
+ })
464
+ .map(IntoSeries::into_series)
465
+ })
466
+ .map(Into::into)
467
+ .map_err(RbPolarsErr::from)
468
+ .map_err(RbErr::from)
469
+ }
470
+
471
+ pub fn str_json_decode(
472
+ rb: &Ruby,
473
+ self_: &Self,
474
+ infer_schema_length: Option<usize>,
475
+ ) -> RbResult<Self> {
476
+ rb.enter_polars(|| {
477
+ let lock = self_.series.read();
478
+ lock.str()?
479
+ .json_decode(None, infer_schema_length)
480
+ .map(|s| s.with_name(lock.name().clone()))
481
+ })
482
+ .map(Into::into)
483
+ .map_err(RbPolarsErr::from)
484
+ .map_err(RbErr::from)
593
485
  }
594
486
  }
595
487
 
@@ -600,7 +492,7 @@ macro_rules! impl_set_with_mask {
600
492
  filter: &RbSeries,
601
493
  value: Option<$native>,
602
494
  ) -> PolarsResult<Series> {
603
- let binding = filter.series.borrow();
495
+ let binding = filter.series.read();
604
496
  let mask = binding.bool()?;
605
497
  let ca = series.$cast()?;
606
498
  let new = ca.set(mask, value)?;
@@ -608,10 +500,13 @@ macro_rules! impl_set_with_mask {
608
500
  }
609
501
 
610
502
  impl RbSeries {
611
- pub fn $name(&self, filter: &RbSeries, value: Option<$native>) -> RbResult<Self> {
612
- let series =
613
- $name(&self.series.borrow(), filter, value).map_err(RbPolarsErr::from)?;
614
- Ok(Self::new(series))
503
+ pub fn $name(
504
+ rb: &Ruby,
505
+ self_: &Self,
506
+ filter: &RbSeries,
507
+ value: Option<$native>,
508
+ ) -> RbResult<Self> {
509
+ rb.enter_polars_series(|| $name(&self_.series.read(), filter, value))
615
510
  }
616
511
  }
617
512
  };
@@ -629,15 +524,3 @@ impl_set_with_mask!(set_with_mask_i16, i16, i16, Int16);
629
524
  impl_set_with_mask!(set_with_mask_i32, i32, i32, Int32);
630
525
  impl_set_with_mask!(set_with_mask_i64, i64, i64, Int64);
631
526
  impl_set_with_mask!(set_with_mask_bool, bool, bool, Boolean);
632
-
633
- impl RbSeries {
634
- pub fn extend_constant(&self, value: Wrap<AnyValue>, n: usize) -> RbResult<Self> {
635
- Ok(self
636
- .series
637
- .borrow()
638
- .clone()
639
- .extend_constant(value.0, n)
640
- .map_err(RbPolarsErr::from)?
641
- .into())
642
- }
643
- }