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,1167 +1,321 @@
1
- use magnus::{class, prelude::*, typed_data::Obj, IntoValue, TryConvert, Value};
2
- use polars::prelude::*;
1
+ use magnus::{IntoValue, TryConvert};
3
2
 
4
3
  use super::*;
5
- use crate::series::RbSeries;
6
- use crate::{ObjectValue, RbResult};
4
+ use crate::Wrap;
5
+ use crate::error::RbPolarsErr;
6
+ use crate::prelude::ObjectValue;
7
+ use crate::ruby::utils::TryIntoValue;
7
8
 
8
- /// Find the output type and dispatch to that implementation.
9
- fn infer_and_finish<'a, A: ApplyLambda<'a>>(
10
- applyer: &'a A,
11
- lambda: Value,
12
- out: Value,
13
- null_count: usize,
14
- ) -> RbResult<RbSeries> {
15
- if out.is_kind_of(class::true_class()) || out.is_kind_of(class::false_class()) {
16
- let first_value = bool::try_convert(out).unwrap();
17
- applyer
18
- .apply_lambda_with_bool_out_type(lambda, null_count, Some(first_value))
19
- .map(|ca| ca.into_series().into())
20
- } else if out.is_kind_of(class::float()) {
21
- let first_value = f64::try_convert(out).unwrap();
22
- applyer
23
- .apply_lambda_with_primitive_out_type::<Float64Type>(
24
- lambda,
25
- null_count,
26
- Some(first_value),
27
- )
28
- .map(|ca| ca.into_series().into())
29
- } else if out.is_kind_of(class::string()) {
30
- let first_value = String::try_convert(out).unwrap();
31
- applyer
32
- .apply_lambda_with_utf8_out_type(lambda, null_count, Some(first_value.as_str()))
33
- .map(|ca| ca.into_series().into())
34
- } else if out.respond_to("_s", true)? {
35
- let rb_rbseries: &RbSeries = out.funcall("_s", ()).unwrap();
36
- let series = rb_rbseries.series.borrow();
37
- let dt = series.dtype();
38
- applyer
39
- .apply_lambda_with_list_out_type(lambda, null_count, &series, dt)
40
- .map(|ca| ca.into_series().into())
41
- } else if out.is_kind_of(class::array()) {
42
- todo!()
43
- } else if out.is_kind_of(class::hash()) {
44
- let first = Wrap::<AnyValue<'_>>::try_convert(out)?;
45
- applyer.apply_into_struct(lambda, null_count, first.0)
46
- }
47
- // this succeeds for numpy ints as well, where checking if it is pyint fails
48
- // we do this later in the chain so that we don't extract integers from string chars.
49
- else if i64::try_convert(out).is_ok() {
50
- let first_value = i64::try_convert(out).unwrap();
51
- applyer
52
- .apply_lambda_with_primitive_out_type::<Int64Type>(
53
- lambda,
54
- null_count,
55
- Some(first_value),
56
- )
57
- .map(|ca| ca.into_series().into())
58
- } else if let Ok(av) = Wrap::<AnyValue>::try_convert(out) {
59
- applyer
60
- .apply_extract_any_values(lambda, null_count, av.0)
61
- .map(|s| s.into())
62
- } else {
63
- applyer
64
- .apply_lambda_with_object_out_type(lambda, null_count, Some(out.into()))
65
- .map(|ca| ca.into_series().into())
66
- }
67
- }
68
-
69
- pub trait ApplyLambda<'a> {
70
- fn apply_lambda_unknown(&'a self, _lambda: Value) -> RbResult<RbSeries>;
71
-
72
- // Used to store a struct type
73
- fn apply_into_struct(
74
- &'a self,
75
- lambda: Value,
76
- init_null_count: usize,
77
- first_value: AnyValue<'a>,
78
- ) -> RbResult<RbSeries>;
79
-
80
- /// Apply a lambda with a primitive output type
81
- fn apply_lambda_with_primitive_out_type<D>(
82
- &'a self,
83
- lambda: Value,
84
- init_null_count: usize,
85
- first_value: Option<D::Native>,
86
- ) -> RbResult<ChunkedArray<D>>
87
- where
88
- D: RbArrowPrimitiveType,
89
- D::Native: IntoValue + TryConvert;
9
+ pub trait ApplyLambdaGeneric {
10
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series>;
90
11
 
91
- /// Apply a lambda with a boolean output type
92
- fn apply_lambda_with_bool_out_type(
93
- &'a self,
94
- lambda: Value,
95
- init_null_count: usize,
96
- first_value: Option<bool>,
97
- ) -> RbResult<ChunkedArray<BooleanType>>;
98
-
99
- /// Apply a lambda with utf8 output type
100
- fn apply_lambda_with_utf8_out_type(
101
- &'a self,
102
- lambda: Value,
103
- init_null_count: usize,
104
- first_value: Option<&str>,
105
- ) -> RbResult<StringChunked>;
106
-
107
- /// Apply a lambda with list output type
108
- fn apply_lambda_with_list_out_type(
109
- &'a self,
110
- lambda: Value,
111
- init_null_count: usize,
112
- first_value: &Series,
113
- dt: &DataType,
114
- ) -> RbResult<ListChunked>;
115
-
116
- fn apply_extract_any_values(
117
- &'a self,
12
+ fn apply_generic_with_dtype(
13
+ &self,
14
+ rb: &Ruby,
118
15
  lambda: Value,
119
- init_null_count: usize,
120
- first_value: AnyValue<'a>,
16
+ datatype: &DataType,
17
+ skip_nulls: bool,
121
18
  ) -> RbResult<Series>;
122
-
123
- /// Apply a lambda with list output type
124
- fn apply_lambda_with_object_out_type(
125
- &'a self,
126
- lambda: Value,
127
- init_null_count: usize,
128
- first_value: Option<ObjectValue>,
129
- ) -> RbResult<ObjectChunked<ObjectValue>>;
130
19
  }
131
20
 
132
- pub fn call_lambda<T>(lambda: Value, in_val: T) -> RbResult<Value>
133
- where
134
- T: IntoValue,
135
- {
136
- lambda.funcall("call", (in_val,))
137
- }
138
-
139
- pub(crate) fn call_lambda_and_extract<T, S>(lambda: Value, in_val: T) -> RbResult<S>
140
- where
141
- T: IntoValue,
142
- S: TryConvert,
143
- {
144
- match call_lambda(lambda, in_val) {
145
- Ok(out) => S::try_convert(out),
146
- Err(e) => panic!("ruby function failed {}", e),
147
- }
148
- }
149
-
150
- fn call_lambda_series_out<T>(lambda: Value, in_val: T) -> RbResult<Series>
21
+ fn call_and_collect_anyvalues<T, I>(
22
+ rb: &Ruby,
23
+ lambda: Value,
24
+ len: usize,
25
+ iter: I,
26
+ skip_nulls: bool,
27
+ ) -> RbResult<Vec<AnyValue<'static>>>
151
28
  where
152
- T: IntoValue,
29
+ T: TryIntoValue,
30
+ I: Iterator<Item = Option<T>>,
153
31
  {
154
- let out: Value = lambda.funcall("call", (in_val,))?;
155
- let py_series: Obj<RbSeries> = out.funcall("_s", ())?;
156
- let tmp = py_series.series.borrow();
157
- Ok(tmp.clone())
158
- }
159
-
160
- impl<'a> ApplyLambda<'a> for BooleanChunked {
161
- fn apply_lambda_unknown(&'a self, lambda: Value) -> RbResult<RbSeries> {
162
- let mut null_count = 0;
163
- for opt_v in self.into_iter() {
164
- if let Some(v) = opt_v {
165
- let arg = (v,);
166
- let out: Value = lambda.funcall("call", arg)?;
167
- if out.is_nil() {
168
- null_count += 1;
169
- continue;
170
- }
171
- return infer_and_finish(self, lambda, out, null_count);
172
- } else {
173
- null_count += 1
32
+ let mut avs = Vec::with_capacity(len);
33
+ for opt_val in iter {
34
+ let arg = match opt_val {
35
+ None if skip_nulls => {
36
+ avs.push(AnyValue::Null);
37
+ continue;
174
38
  }
175
- }
176
- Ok(Self::full_null(self.name().clone(), self.len())
177
- .into_series()
178
- .into())
39
+ None => rb.qnil().into_value_with(rb),
40
+ Some(val) => val.try_into_value_with(rb)?,
41
+ };
42
+ let av: Option<Wrap<AnyValue>> = lambda.funcall("call", (arg,))?;
43
+ avs.push(av.map(|w| w.0).unwrap_or(AnyValue::Null));
179
44
  }
45
+ Ok(avs)
46
+ }
180
47
 
181
- fn apply_into_struct(
182
- &'a self,
183
- lambda: Value,
184
- init_null_count: usize,
185
- first_value: AnyValue<'a>,
186
- ) -> RbResult<RbSeries> {
187
- let skip = 1;
188
- if !self.has_nulls() {
189
- let it = self
190
- .into_no_null_iter()
191
- .skip(init_null_count + skip)
192
- .map(|val| call_lambda(lambda, val).ok());
193
- iterator_to_struct(
194
- it,
195
- init_null_count,
196
- first_value,
197
- self.name().clone(),
198
- self.len(),
199
- )
200
- } else {
201
- let it = self
202
- .into_iter()
203
- .skip(init_null_count + skip)
204
- .map(|opt_val| opt_val.and_then(|val| call_lambda(lambda, val).ok()));
205
- iterator_to_struct(
206
- it,
207
- init_null_count,
208
- first_value,
209
- self.name().clone(),
210
- self.len(),
211
- )
212
- }
213
- }
214
-
215
- fn apply_lambda_with_primitive_out_type<D>(
216
- &'a self,
217
- lambda: Value,
218
- init_null_count: usize,
219
- first_value: Option<D::Native>,
220
- ) -> RbResult<ChunkedArray<D>>
221
- where
222
- D: RbArrowPrimitiveType,
223
- D::Native: IntoValue + TryConvert,
224
- {
225
- let skip = usize::from(first_value.is_some());
226
- if init_null_count == self.len() {
227
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
228
- } else if !self.has_nulls() {
229
- let it = self
230
- .into_no_null_iter()
231
- .skip(init_null_count + skip)
232
- .map(|val| call_lambda_and_extract(lambda, val).ok());
233
- Ok(iterator_to_primitive(
234
- it,
235
- init_null_count,
236
- first_value,
237
- self.name().clone(),
238
- self.len(),
239
- ))
240
- } else {
241
- let it = self
242
- .into_iter()
243
- .skip(init_null_count + skip)
244
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
245
- Ok(iterator_to_primitive(
246
- it,
247
- init_null_count,
248
- first_value,
249
- self.name().clone(),
250
- self.len(),
251
- ))
252
- }
253
- }
254
-
255
- fn apply_lambda_with_bool_out_type(
256
- &'a self,
257
- lambda: Value,
258
- init_null_count: usize,
259
- first_value: Option<bool>,
260
- ) -> RbResult<BooleanChunked> {
261
- let skip = usize::from(first_value.is_some());
262
- if init_null_count == self.len() {
263
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
264
- } else if !self.has_nulls() {
265
- let it = self
266
- .into_no_null_iter()
267
- .skip(init_null_count + skip)
268
- .map(|val| call_lambda_and_extract(lambda, val).ok());
269
- Ok(iterator_to_bool(
270
- it,
271
- init_null_count,
272
- first_value,
273
- self.name().clone(),
274
- self.len(),
275
- ))
276
- } else {
277
- let it = self
278
- .into_iter()
279
- .skip(init_null_count + skip)
280
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
281
- Ok(iterator_to_bool(
282
- it,
283
- init_null_count,
284
- first_value,
285
- self.name().clone(),
286
- self.len(),
287
- ))
288
- }
289
- }
290
-
291
- fn apply_lambda_with_utf8_out_type(
292
- &'a self,
293
- lambda: Value,
294
- init_null_count: usize,
295
- first_value: Option<&str>,
296
- ) -> RbResult<StringChunked> {
297
- let skip = usize::from(first_value.is_some());
298
- if init_null_count == self.len() {
299
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
300
- } else if !self.has_nulls() {
301
- let it = self
302
- .into_no_null_iter()
303
- .skip(init_null_count + skip)
304
- .map(|val| call_lambda_and_extract(lambda, val).ok());
305
-
306
- Ok(iterator_to_utf8(
307
- it,
308
- init_null_count,
309
- first_value,
310
- self.name().clone(),
311
- self.len(),
312
- ))
313
- } else {
314
- let it = self
315
- .into_iter()
316
- .skip(init_null_count + skip)
317
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
318
- Ok(iterator_to_utf8(
319
- it,
320
- init_null_count,
321
- first_value,
322
- self.name().clone(),
323
- self.len(),
324
- ))
325
- }
326
- }
327
-
328
- fn apply_lambda_with_list_out_type(
329
- &'a self,
330
- lambda: Value,
331
- init_null_count: usize,
332
- first_value: &Series,
333
- dt: &DataType,
334
- ) -> RbResult<ListChunked> {
335
- let skip = 1;
336
- if init_null_count == self.len() {
337
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
338
- } else if !self.has_nulls() {
339
- let it = self
340
- .into_no_null_iter()
341
- .skip(init_null_count + skip)
342
- .map(|val| call_lambda_series_out(lambda, val).ok());
343
-
344
- iterator_to_list(
345
- dt,
346
- it,
347
- init_null_count,
348
- Some(first_value),
349
- self.name().clone(),
350
- self.len(),
351
- )
352
- } else {
353
- let it = self
354
- .into_iter()
355
- .skip(init_null_count + skip)
356
- .map(|opt_val| opt_val.and_then(|val| call_lambda_series_out(lambda, val).ok()));
357
- iterator_to_list(
358
- dt,
359
- it,
360
- init_null_count,
361
- Some(first_value),
362
- self.name().clone(),
363
- self.len(),
364
- )
365
- }
48
+ impl ApplyLambdaGeneric for BooleanChunked {
49
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
50
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
51
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
366
52
  }
367
53
 
368
- fn apply_extract_any_values(
369
- &'a self,
54
+ fn apply_generic_with_dtype(
55
+ &self,
56
+ rb: &Ruby,
370
57
  lambda: Value,
371
- init_null_count: usize,
372
- first_value: AnyValue<'a>,
58
+ datatype: &DataType,
59
+ skip_nulls: bool,
373
60
  ) -> RbResult<Series> {
374
- let mut avs = Vec::with_capacity(self.len());
375
- avs.extend(std::iter::repeat(AnyValue::Null).take(init_null_count));
376
- avs.push(first_value);
377
-
378
- if self.null_count() > 0 {
379
- let iter = self.into_iter().skip(init_null_count + 1).map(|opt_val| {
380
- let out_wrapped = match opt_val {
381
- None => Wrap(AnyValue::Null),
382
- Some(val) => call_lambda_and_extract(lambda, val).unwrap(),
383
- };
384
- out_wrapped.0
385
- });
386
- avs.extend(iter);
387
- } else {
388
- let iter = self
389
- .into_no_null_iter()
390
- .skip(init_null_count + 1)
391
- .map(|val| {
392
- call_lambda_and_extract::<_, Wrap<AnyValue>>(lambda, val)
393
- .unwrap()
394
- .0
395
- });
396
- avs.extend(iter);
397
- }
398
- Ok(Series::new(self.name().clone(), &avs))
399
- }
400
-
401
- fn apply_lambda_with_object_out_type(
402
- &'a self,
403
- lambda: Value,
404
- init_null_count: usize,
405
- first_value: Option<ObjectValue>,
406
- ) -> RbResult<ObjectChunked<ObjectValue>> {
407
- let skip = usize::from(first_value.is_some());
408
- if init_null_count == self.len() {
409
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
410
- } else if !self.has_nulls() {
411
- let it = self
412
- .into_no_null_iter()
413
- .skip(init_null_count + skip)
414
- .map(|val| call_lambda_and_extract(lambda, val).ok());
415
-
416
- Ok(iterator_to_object(
417
- it,
418
- init_null_count,
419
- first_value,
420
- self.name().clone(),
421
- self.len(),
422
- ))
423
- } else {
424
- let it = self
425
- .into_iter()
426
- .skip(init_null_count + skip)
427
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
428
- Ok(iterator_to_object(
429
- it,
430
- init_null_count,
431
- first_value,
432
- self.name().clone(),
433
- self.len(),
434
- ))
435
- }
61
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
62
+ Ok(
63
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
64
+ .map_err(RbPolarsErr::from)?,
65
+ )
436
66
  }
437
67
  }
438
68
 
439
- impl<'a, T> ApplyLambda<'a> for ChunkedArray<T>
69
+ impl<T> ApplyLambdaGeneric for ChunkedArray<T>
440
70
  where
441
- T: RbArrowPrimitiveType + PolarsNumericType,
71
+ T: RbPolarsNumericType,
442
72
  T::Native: IntoValue + TryConvert,
443
- ChunkedArray<T>: IntoSeries,
444
73
  {
445
- fn apply_lambda_unknown(&'a self, lambda: Value) -> RbResult<RbSeries> {
446
- let mut null_count = 0;
447
- for opt_v in self.into_iter() {
448
- if let Some(v) = opt_v {
449
- let arg = (v,);
450
- let out: Value = lambda.funcall("call", arg)?;
451
- if out.is_nil() {
452
- null_count += 1;
453
- continue;
454
- }
455
- return infer_and_finish(self, lambda, out, null_count);
456
- } else {
457
- null_count += 1
458
- }
459
- }
460
- Ok(Self::full_null(self.name().clone(), self.len())
461
- .into_series()
462
- .into())
74
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
75
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
76
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
463
77
  }
464
78
 
465
- fn apply_into_struct(
466
- &'a self,
467
- lambda: Value,
468
- init_null_count: usize,
469
- first_value: AnyValue<'a>,
470
- ) -> RbResult<RbSeries> {
471
- let skip = 1;
472
- if !self.has_nulls() {
473
- let it = self
474
- .into_no_null_iter()
475
- .skip(init_null_count + skip)
476
- .map(|val| call_lambda(lambda, val).ok());
477
- iterator_to_struct(
478
- it,
479
- init_null_count,
480
- first_value,
481
- self.name().clone(),
482
- self.len(),
483
- )
484
- } else {
485
- let it = self
486
- .into_iter()
487
- .skip(init_null_count + skip)
488
- .map(|opt_val| opt_val.and_then(|val| call_lambda(lambda, val).ok()));
489
- iterator_to_struct(
490
- it,
491
- init_null_count,
492
- first_value,
493
- self.name().clone(),
494
- self.len(),
495
- )
496
- }
497
- }
498
-
499
- fn apply_lambda_with_primitive_out_type<D>(
500
- &'a self,
79
+ fn apply_generic_with_dtype(
80
+ &self,
81
+ rb: &Ruby,
501
82
  lambda: Value,
502
- init_null_count: usize,
503
- first_value: Option<D::Native>,
504
- ) -> RbResult<ChunkedArray<D>>
505
- where
506
- D: RbArrowPrimitiveType,
507
- D::Native: IntoValue + TryConvert,
508
- {
509
- let skip = usize::from(first_value.is_some());
510
- if init_null_count == self.len() {
511
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
512
- } else if !self.has_nulls() {
513
- let it = self
514
- .into_no_null_iter()
515
- .skip(init_null_count + skip)
516
- .map(|val| call_lambda_and_extract(lambda, val).ok());
517
- Ok(iterator_to_primitive(
518
- it,
519
- init_null_count,
520
- first_value,
521
- self.name().clone(),
522
- self.len(),
523
- ))
524
- } else {
525
- let it = self
526
- .into_iter()
527
- .skip(init_null_count + skip)
528
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
529
- Ok(iterator_to_primitive(
530
- it,
531
- init_null_count,
532
- first_value,
533
- self.name().clone(),
534
- self.len(),
535
- ))
536
- }
83
+ datatype: &DataType,
84
+ skip_nulls: bool,
85
+ ) -> RbResult<Series> {
86
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
87
+ Ok(
88
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
89
+ .map_err(RbPolarsErr::from)?,
90
+ )
537
91
  }
92
+ }
538
93
 
539
- fn apply_lambda_with_bool_out_type(
540
- &'a self,
541
- lambda: Value,
542
- init_null_count: usize,
543
- first_value: Option<bool>,
544
- ) -> RbResult<BooleanChunked> {
545
- let skip = usize::from(first_value.is_some());
546
- if init_null_count == self.len() {
547
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
548
- } else if !self.has_nulls() {
549
- let it = self
550
- .into_no_null_iter()
551
- .skip(init_null_count + skip)
552
- .map(|val| call_lambda_and_extract(lambda, val).ok());
553
- Ok(iterator_to_bool(
554
- it,
555
- init_null_count,
556
- first_value,
557
- self.name().clone(),
558
- self.len(),
559
- ))
560
- } else {
561
- let it = self
562
- .into_iter()
563
- .skip(init_null_count + skip)
564
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
565
- Ok(iterator_to_bool(
566
- it,
567
- init_null_count,
568
- first_value,
569
- self.name().clone(),
570
- self.len(),
571
- ))
572
- }
94
+ impl ApplyLambdaGeneric for StringChunked {
95
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
96
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
97
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
573
98
  }
574
99
 
575
- fn apply_lambda_with_utf8_out_type(
576
- &'a self,
100
+ fn apply_generic_with_dtype(
101
+ &self,
102
+ rb: &Ruby,
577
103
  lambda: Value,
578
- init_null_count: usize,
579
- first_value: Option<&str>,
580
- ) -> RbResult<StringChunked> {
581
- let skip = usize::from(first_value.is_some());
582
- if init_null_count == self.len() {
583
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
584
- } else if !self.has_nulls() {
585
- let it = self
586
- .into_no_null_iter()
587
- .skip(init_null_count + skip)
588
- .map(|val| call_lambda_and_extract(lambda, val).ok());
589
-
590
- Ok(iterator_to_utf8(
591
- it,
592
- init_null_count,
593
- first_value,
594
- self.name().clone(),
595
- self.len(),
596
- ))
597
- } else {
598
- let it = self
599
- .into_iter()
600
- .skip(init_null_count + skip)
601
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
602
- Ok(iterator_to_utf8(
603
- it,
604
- init_null_count,
605
- first_value,
606
- self.name().clone(),
607
- self.len(),
608
- ))
609
- }
104
+ datatype: &DataType,
105
+ skip_nulls: bool,
106
+ ) -> RbResult<Series> {
107
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), self.iter(), skip_nulls)?;
108
+ Ok(
109
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
110
+ .map_err(RbPolarsErr::from)?,
111
+ )
610
112
  }
113
+ }
611
114
 
612
- fn apply_lambda_with_list_out_type(
613
- &'a self,
614
- lambda: Value,
615
- init_null_count: usize,
616
- first_value: &Series,
617
- dt: &DataType,
618
- ) -> RbResult<ListChunked> {
619
- let skip = 1;
620
- if init_null_count == self.len() {
621
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
622
- } else if !self.has_nulls() {
623
- let it = self
624
- .into_no_null_iter()
625
- .skip(init_null_count + skip)
626
- .map(|val| call_lambda_series_out(lambda, val).ok());
627
-
628
- iterator_to_list(
629
- dt,
630
- it,
631
- init_null_count,
632
- Some(first_value),
633
- self.name().clone(),
634
- self.len(),
635
- )
636
- } else {
637
- let it = self
638
- .into_iter()
639
- .skip(init_null_count + skip)
640
- .map(|opt_val| opt_val.and_then(|val| call_lambda_series_out(lambda, val).ok()));
641
- iterator_to_list(
642
- dt,
643
- it,
644
- init_null_count,
645
- Some(first_value),
646
- self.name().clone(),
647
- self.len(),
648
- )
649
- }
115
+ impl ApplyLambdaGeneric for ListChunked {
116
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
117
+ let it = self.series_iter().map(|opt_s| opt_s.map(Wrap));
118
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
119
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
650
120
  }
651
121
 
652
- fn apply_extract_any_values(
653
- &'a self,
122
+ fn apply_generic_with_dtype(
123
+ &self,
124
+ rb: &Ruby,
654
125
  lambda: Value,
655
- init_null_count: usize,
656
- first_value: AnyValue<'a>,
126
+ datatype: &DataType,
127
+ skip_nulls: bool,
657
128
  ) -> RbResult<Series> {
658
- let mut avs = Vec::with_capacity(self.len());
659
- avs.extend(std::iter::repeat(AnyValue::Null).take(init_null_count));
660
- avs.push(first_value);
661
-
662
- if self.null_count() > 0 {
663
- let iter = self.into_iter().skip(init_null_count + 1).map(|opt_val| {
664
- let out_wrapped = match opt_val {
665
- None => Wrap(AnyValue::Null),
666
- Some(val) => call_lambda_and_extract(lambda, val).unwrap(),
667
- };
668
- out_wrapped.0
669
- });
670
- avs.extend(iter);
671
- } else {
672
- let iter = self
673
- .into_no_null_iter()
674
- .skip(init_null_count + 1)
675
- .map(|val| {
676
- call_lambda_and_extract::<_, Wrap<AnyValue>>(lambda, val)
677
- .unwrap()
678
- .0
679
- });
680
- avs.extend(iter);
681
- }
682
- Ok(Series::new(self.name().clone(), &avs))
683
- }
684
-
685
- fn apply_lambda_with_object_out_type(
686
- &'a self,
687
- lambda: Value,
688
- init_null_count: usize,
689
- first_value: Option<ObjectValue>,
690
- ) -> RbResult<ObjectChunked<ObjectValue>> {
691
- let skip = usize::from(first_value.is_some());
692
- if init_null_count == self.len() {
693
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
694
- } else if !self.has_nulls() {
695
- let it = self
696
- .into_no_null_iter()
697
- .skip(init_null_count + skip)
698
- .map(|val| call_lambda_and_extract(lambda, val).ok());
699
-
700
- Ok(iterator_to_object(
701
- it,
702
- init_null_count,
703
- first_value,
704
- self.name().clone(),
705
- self.len(),
706
- ))
707
- } else {
708
- let it = self
709
- .into_iter()
710
- .skip(init_null_count + skip)
711
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
712
- Ok(iterator_to_object(
713
- it,
714
- init_null_count,
715
- first_value,
716
- self.name().clone(),
717
- self.len(),
718
- ))
719
- }
129
+ let it = self.series_iter().map(|opt_s| opt_s.map(Wrap));
130
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
131
+ Ok(
132
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
133
+ .map_err(RbPolarsErr::from)?,
134
+ )
720
135
  }
721
136
  }
722
137
 
723
- impl<'a> ApplyLambda<'a> for StringChunked {
724
- fn apply_lambda_unknown(&'a self, lambda: Value) -> RbResult<RbSeries> {
725
- let mut null_count = 0;
726
- for opt_v in self.into_iter() {
727
- if let Some(v) = opt_v {
728
- let arg = (v,);
729
- let out: Value = lambda.funcall("call", arg)?;
730
- if out.is_nil() {
731
- null_count += 1;
732
- continue;
733
- }
734
- return infer_and_finish(self, lambda, out, null_count);
735
- } else {
736
- null_count += 1
737
- }
738
- }
739
- Ok(Self::full_null(self.name().clone(), self.len())
740
- .into_series()
741
- .into())
742
- }
743
-
744
- fn apply_into_struct(
745
- &'a self,
746
- lambda: Value,
747
- init_null_count: usize,
748
- first_value: AnyValue<'a>,
749
- ) -> RbResult<RbSeries> {
750
- let skip = 1;
751
- if !self.has_nulls() {
752
- let it = self
753
- .into_no_null_iter()
754
- .skip(init_null_count + skip)
755
- .map(|val| call_lambda(lambda, val).ok());
756
- iterator_to_struct(
757
- it,
758
- init_null_count,
759
- first_value,
760
- self.name().clone(),
761
- self.len(),
762
- )
763
- } else {
764
- let it = self
765
- .into_iter()
766
- .skip(init_null_count + skip)
767
- .map(|opt_val| opt_val.and_then(|val| call_lambda(lambda, val).ok()));
768
- iterator_to_struct(
769
- it,
770
- init_null_count,
771
- first_value,
772
- self.name().clone(),
773
- self.len(),
774
- )
775
- }
138
+ impl ApplyLambdaGeneric for ArrayChunked {
139
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
140
+ let it = self.series_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
141
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
142
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
776
143
  }
777
144
 
778
- fn apply_lambda_with_primitive_out_type<D>(
779
- &'a self,
145
+ fn apply_generic_with_dtype(
146
+ &self,
147
+ rb: &Ruby,
780
148
  lambda: Value,
781
- init_null_count: usize,
782
- first_value: Option<D::Native>,
783
- ) -> RbResult<ChunkedArray<D>>
784
- where
785
- D: RbArrowPrimitiveType,
786
- D::Native: IntoValue + TryConvert,
787
- {
788
- let skip = usize::from(first_value.is_some());
789
- if init_null_count == self.len() {
790
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
791
- } else if !self.has_nulls() {
792
- let it = self
793
- .into_no_null_iter()
794
- .skip(init_null_count + skip)
795
- .map(|val| call_lambda_and_extract(lambda, val).ok());
796
- Ok(iterator_to_primitive(
797
- it,
798
- init_null_count,
799
- first_value,
800
- self.name().clone(),
801
- self.len(),
802
- ))
803
- } else {
804
- let it = self
805
- .into_iter()
806
- .skip(init_null_count + skip)
807
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
808
- Ok(iterator_to_primitive(
809
- it,
810
- init_null_count,
811
- first_value,
812
- self.name().clone(),
813
- self.len(),
814
- ))
815
- }
149
+ datatype: &DataType,
150
+ skip_nulls: bool,
151
+ ) -> RbResult<Series> {
152
+ let it = self.series_iter().map(|opt_s| Some(RbSeries::new(opt_s?)));
153
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
154
+ Ok(
155
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
156
+ .map_err(RbPolarsErr::from)?,
157
+ )
816
158
  }
159
+ }
817
160
 
818
- fn apply_lambda_with_bool_out_type(
819
- &'a self,
820
- lambda: Value,
821
- init_null_count: usize,
822
- first_value: Option<bool>,
823
- ) -> RbResult<BooleanChunked> {
824
- let skip = usize::from(first_value.is_some());
825
- if init_null_count == self.len() {
826
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
827
- } else if !self.has_nulls() {
828
- let it = self
829
- .into_no_null_iter()
830
- .skip(init_null_count + skip)
831
- .map(|val| call_lambda_and_extract(lambda, val).ok());
832
- Ok(iterator_to_bool(
833
- it,
834
- init_null_count,
835
- first_value,
836
- self.name().clone(),
837
- self.len(),
838
- ))
839
- } else {
840
- let it = self
841
- .into_iter()
842
- .skip(init_null_count + skip)
843
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
844
- Ok(iterator_to_bool(
845
- it,
846
- init_null_count,
847
- first_value,
848
- self.name().clone(),
849
- self.len(),
850
- ))
851
- }
161
+ impl ApplyLambdaGeneric for ObjectChunked<ObjectValue> {
162
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
163
+ // TODO improve iter
164
+ let avs = call_and_collect_anyvalues(
165
+ rb,
166
+ lambda,
167
+ self.len(),
168
+ self.iter().map(|v| v.cloned()),
169
+ skip_nulls,
170
+ )?;
171
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
852
172
  }
853
173
 
854
- fn apply_lambda_with_utf8_out_type(
174
+ fn apply_generic_with_dtype(
855
175
  &self,
176
+ rb: &Ruby,
856
177
  lambda: Value,
857
- init_null_count: usize,
858
- first_value: Option<&str>,
859
- ) -> RbResult<StringChunked> {
860
- let skip = usize::from(first_value.is_some());
861
- if init_null_count == self.len() {
862
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
863
- } else if !self.has_nulls() {
864
- let it = self
865
- .into_no_null_iter()
866
- .skip(init_null_count + skip)
867
- .map(|val| call_lambda_and_extract(lambda, val).ok());
868
-
869
- Ok(iterator_to_utf8(
870
- it,
871
- init_null_count,
872
- first_value,
873
- self.name().clone(),
874
- self.len(),
875
- ))
876
- } else {
877
- let it = self
878
- .into_iter()
879
- .skip(init_null_count + skip)
880
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
881
- Ok(iterator_to_utf8(
882
- it,
883
- init_null_count,
884
- first_value,
885
- self.name().clone(),
886
- self.len(),
887
- ))
888
- }
178
+ datatype: &DataType,
179
+ skip_nulls: bool,
180
+ ) -> RbResult<Series> {
181
+ // TODO improve iter
182
+ let avs = call_and_collect_anyvalues(
183
+ rb,
184
+ lambda,
185
+ self.len(),
186
+ self.iter().map(|v| v.cloned()),
187
+ skip_nulls,
188
+ )?;
189
+ Ok(
190
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
191
+ .map_err(RbPolarsErr::from)?,
192
+ )
889
193
  }
194
+ }
890
195
 
891
- fn apply_lambda_with_list_out_type(
892
- &'a self,
893
- lambda: Value,
894
- init_null_count: usize,
895
- first_value: &Series,
896
- dt: &DataType,
897
- ) -> RbResult<ListChunked> {
898
- let skip = 1;
899
- if init_null_count == self.len() {
900
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
901
- } else if !self.has_nulls() {
902
- let it = self
903
- .into_no_null_iter()
904
- .skip(init_null_count + skip)
905
- .map(|val| call_lambda_series_out(lambda, val).ok());
906
-
907
- iterator_to_list(
908
- dt,
909
- it,
910
- init_null_count,
911
- Some(first_value),
912
- self.name().clone(),
913
- self.len(),
914
- )
915
- } else {
916
- let it = self
917
- .into_iter()
918
- .skip(init_null_count + skip)
919
- .map(|opt_val| opt_val.and_then(|val| call_lambda_series_out(lambda, val).ok()));
920
- iterator_to_list(
921
- dt,
922
- it,
923
- init_null_count,
924
- Some(first_value),
925
- self.name().clone(),
926
- self.len(),
927
- )
928
- }
196
+ impl ApplyLambdaGeneric for StructChunked {
197
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
198
+ let it = (0..self.len())
199
+ .map(|i| unsafe { self.get_any_value_unchecked(i).null_to_none().map(Wrap) });
200
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
201
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
929
202
  }
930
203
 
931
- fn apply_extract_any_values(
932
- &'a self,
204
+ fn apply_generic_with_dtype(
205
+ &self,
206
+ rb: &Ruby,
933
207
  lambda: Value,
934
- init_null_count: usize,
935
- first_value: AnyValue<'a>,
208
+ datatype: &DataType,
209
+ skip_nulls: bool,
936
210
  ) -> RbResult<Series> {
937
- let mut avs = Vec::with_capacity(self.len());
938
- avs.extend(std::iter::repeat(AnyValue::Null).take(init_null_count));
939
- avs.push(first_value);
940
-
941
- if self.null_count() > 0 {
942
- let iter = self.into_iter().skip(init_null_count + 1).map(|opt_val| {
943
- let out_wrapped = match opt_val {
944
- None => Wrap(AnyValue::Null),
945
- Some(val) => call_lambda_and_extract(lambda, val).unwrap(),
946
- };
947
- out_wrapped.0
948
- });
949
- avs.extend(iter);
950
- } else {
951
- let iter = self
952
- .into_no_null_iter()
953
- .skip(init_null_count + 1)
954
- .map(|val| {
955
- call_lambda_and_extract::<_, Wrap<AnyValue>>(lambda, val)
956
- .unwrap()
957
- .0
958
- });
959
- avs.extend(iter);
960
- }
961
- Ok(Series::new(self.name().clone(), &avs))
962
- }
963
-
964
- fn apply_lambda_with_object_out_type(
965
- &'a self,
966
- lambda: Value,
967
- init_null_count: usize,
968
- first_value: Option<ObjectValue>,
969
- ) -> RbResult<ObjectChunked<ObjectValue>> {
970
- let skip = usize::from(first_value.is_some());
971
- if init_null_count == self.len() {
972
- Ok(ChunkedArray::full_null(self.name().clone(), self.len()))
973
- } else if !self.has_nulls() {
974
- let it = self
975
- .into_no_null_iter()
976
- .skip(init_null_count + skip)
977
- .map(|val| call_lambda_and_extract(lambda, val).ok());
978
-
979
- Ok(iterator_to_object(
980
- it,
981
- init_null_count,
982
- first_value,
983
- self.name().clone(),
984
- self.len(),
985
- ))
986
- } else {
987
- let it = self
988
- .into_iter()
989
- .skip(init_null_count + skip)
990
- .map(|opt_val| opt_val.and_then(|val| call_lambda_and_extract(lambda, val).ok()));
991
- Ok(iterator_to_object(
992
- it,
993
- init_null_count,
994
- first_value,
995
- self.name().clone(),
996
- self.len(),
997
- ))
998
- }
211
+ let it = (0..self.len())
212
+ .map(|i| unsafe { self.get_any_value_unchecked(i).null_to_none().map(Wrap) });
213
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
214
+ Ok(
215
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
216
+ .map_err(RbPolarsErr::from)?,
217
+ )
999
218
  }
1000
219
  }
1001
220
 
1002
- fn iter_struct(ca: &StructChunked) -> impl Iterator<Item = AnyValue> {
1003
- (0..ca.len()).map(|i| unsafe { ca.get_any_value_unchecked(i) })
1004
- }
1005
-
1006
- impl<'a> ApplyLambda<'a> for StructChunked {
1007
- fn apply_lambda_unknown(&'a self, lambda: Value) -> RbResult<RbSeries> {
1008
- let mut null_count = 0;
1009
-
1010
- for val in iter_struct(self) {
1011
- let out: Value = lambda.funcall("call", (Wrap(val),))?;
1012
- if out.is_nil() {
1013
- null_count += 1;
1014
- continue;
1015
- }
1016
- return infer_and_finish(self, lambda, out, null_count);
1017
- }
1018
-
1019
- // todo! full null
1020
- Ok(self.clone().into_series().into())
221
+ impl ApplyLambdaGeneric for BinaryChunked {
222
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
223
+ let avs = call_and_collect_anyvalues(
224
+ rb,
225
+ lambda,
226
+ self.len(),
227
+ self.iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
228
+ skip_nulls,
229
+ )?;
230
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
1021
231
  }
1022
232
 
1023
- fn apply_into_struct(
1024
- &'a self,
233
+ fn apply_generic_with_dtype(
234
+ &self,
235
+ rb: &Ruby,
1025
236
  lambda: Value,
1026
- init_null_count: usize,
1027
- first_value: AnyValue<'a>,
1028
- ) -> RbResult<RbSeries> {
1029
- let skip = 1;
1030
- let it = iter_struct(self).skip(init_null_count + skip).map(|val| {
1031
- let out = lambda.funcall("call", (Wrap(val),)).unwrap();
1032
- Some(out)
1033
- });
1034
- iterator_to_struct(
1035
- it,
1036
- init_null_count,
1037
- first_value,
1038
- self.name().clone(),
237
+ datatype: &DataType,
238
+ skip_nulls: bool,
239
+ ) -> RbResult<Series> {
240
+ let avs = call_and_collect_anyvalues(
241
+ rb,
242
+ lambda,
1039
243
  self.len(),
244
+ self.iter().map(|v| v.map(|v2| rb.str_from_slice(v2))),
245
+ skip_nulls,
246
+ )?;
247
+ Ok(
248
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
249
+ .map_err(RbPolarsErr::from)?,
1040
250
  )
1041
251
  }
252
+ }
1042
253
 
1043
- fn apply_lambda_with_primitive_out_type<D>(
1044
- &'a self,
1045
- lambda: Value,
1046
- init_null_count: usize,
1047
- first_value: Option<D::Native>,
1048
- ) -> RbResult<ChunkedArray<D>>
1049
- where
1050
- D: RbArrowPrimitiveType,
1051
- D::Native: IntoValue + TryConvert,
1052
- {
1053
- let skip = usize::from(first_value.is_some());
1054
- let it = iter_struct(self)
1055
- .skip(init_null_count + skip)
1056
- .map(|val| call_lambda_and_extract(lambda, Wrap(val)).ok());
1057
-
1058
- Ok(iterator_to_primitive(
1059
- it,
1060
- init_null_count,
1061
- first_value,
1062
- self.name().clone(),
1063
- self.len(),
1064
- ))
254
+ impl<L, P> ApplyLambdaGeneric for Logical<L, P>
255
+ where
256
+ L: PolarsDataType,
257
+ P: PolarsDataType,
258
+ Logical<L, P>: LogicalType,
259
+ {
260
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
261
+ let it = (0..self.len())
262
+ .map(|i| unsafe { self.get_any_value_unchecked(i).null_to_none().map(Wrap) });
263
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
264
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
1065
265
  }
1066
266
 
1067
- fn apply_lambda_with_bool_out_type(
1068
- &'a self,
267
+ fn apply_generic_with_dtype(
268
+ &self,
269
+ rb: &Ruby,
1069
270
  lambda: Value,
1070
- init_null_count: usize,
1071
- first_value: Option<bool>,
1072
- ) -> RbResult<BooleanChunked> {
1073
- let skip = usize::from(first_value.is_some());
1074
- let it = iter_struct(self)
1075
- .skip(init_null_count + skip)
1076
- .map(|val| call_lambda_and_extract(lambda, Wrap(val)).ok());
1077
-
1078
- Ok(iterator_to_bool(
1079
- it,
1080
- init_null_count,
1081
- first_value,
1082
- self.name().clone(),
1083
- self.len(),
1084
- ))
271
+ datatype: &DataType,
272
+ skip_nulls: bool,
273
+ ) -> RbResult<Series> {
274
+ let it = (0..self.len())
275
+ .map(|i| unsafe { self.get_any_value_unchecked(i).null_to_none().map(Wrap) });
276
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
277
+ Ok(
278
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
279
+ .map_err(RbPolarsErr::from)?,
280
+ )
1085
281
  }
282
+ }
1086
283
 
1087
- fn apply_lambda_with_utf8_out_type(
1088
- &'a self,
1089
- lambda: Value,
1090
- init_null_count: usize,
1091
- first_value: Option<&str>,
1092
- ) -> RbResult<StringChunked> {
1093
- let skip = usize::from(first_value.is_some());
1094
- let it = iter_struct(self)
1095
- .skip(init_null_count + skip)
1096
- .map(|val| call_lambda_and_extract(lambda, Wrap(val)).ok());
1097
-
1098
- Ok(iterator_to_utf8(
1099
- it,
1100
- init_null_count,
1101
- first_value,
1102
- self.name().clone(),
1103
- self.len(),
1104
- ))
284
+ impl ApplyLambdaGeneric for NullChunked {
285
+ fn apply_generic(&self, rb: &Ruby, lambda: Value, skip_nulls: bool) -> RbResult<Series> {
286
+ let it = (0..self.len()).map(|_| None::<Wrap<AnyValue<'static>>>);
287
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
288
+ Ok(Series::from_any_values(self.name().clone(), &avs, true).map_err(RbPolarsErr::from)?)
1105
289
  }
1106
290
 
1107
- fn apply_lambda_with_list_out_type(
1108
- &'a self,
291
+ fn apply_generic_with_dtype(
292
+ &self,
293
+ rb: &Ruby,
1109
294
  lambda: Value,
1110
- init_null_count: usize,
1111
- first_value: &Series,
1112
- dt: &DataType,
1113
- ) -> RbResult<ListChunked> {
1114
- let skip = 1;
1115
- let it = iter_struct(self)
1116
- .skip(init_null_count + skip)
1117
- .map(|val| call_lambda_series_out(lambda, Wrap(val)).ok());
1118
- iterator_to_list(
1119
- dt,
1120
- it,
1121
- init_null_count,
1122
- Some(first_value),
1123
- self.name().clone(),
1124
- self.len(),
295
+ datatype: &DataType,
296
+ skip_nulls: bool,
297
+ ) -> RbResult<Series> {
298
+ let it = (0..self.len()).map(|_| None::<Wrap<AnyValue<'static>>>);
299
+ let avs = call_and_collect_anyvalues(rb, lambda, self.len(), it, skip_nulls)?;
300
+ Ok(
301
+ Series::from_any_values_and_dtype(self.name().clone(), &avs, datatype, true)
302
+ .map_err(RbPolarsErr::from)?,
1125
303
  )
1126
304
  }
305
+ }
1127
306
 
1128
- fn apply_extract_any_values(
1129
- &'a self,
1130
- lambda: Value,
1131
- init_null_count: usize,
1132
- first_value: AnyValue<'a>,
1133
- ) -> RbResult<Series> {
1134
- let mut avs = Vec::with_capacity(self.len());
1135
- avs.extend(std::iter::repeat(AnyValue::Null).take(init_null_count));
1136
- avs.push(first_value);
1137
-
1138
- let iter = iter_struct(self).skip(init_null_count + 1).map(|val| {
1139
- call_lambda_and_extract::<_, Wrap<AnyValue>>(lambda, Wrap(val))
1140
- .unwrap()
1141
- .0
1142
- });
1143
- avs.extend(iter);
1144
-
1145
- Ok(Series::new(self.name().clone(), &avs))
307
+ impl ApplyLambdaGeneric for ExtensionChunked {
308
+ fn apply_generic(&self, _rb: &Ruby, _lambda: Value, _skip_nulls: bool) -> RbResult<Series> {
309
+ unreachable!()
1146
310
  }
1147
311
 
1148
- fn apply_lambda_with_object_out_type(
1149
- &'a self,
1150
- lambda: Value,
1151
- init_null_count: usize,
1152
- first_value: Option<ObjectValue>,
1153
- ) -> RbResult<ObjectChunked<ObjectValue>> {
1154
- let skip = usize::from(first_value.is_some());
1155
- let it = iter_struct(self)
1156
- .skip(init_null_count + skip)
1157
- .map(|val| call_lambda_and_extract(lambda, Wrap(val)).ok());
1158
-
1159
- Ok(iterator_to_object(
1160
- it,
1161
- init_null_count,
1162
- first_value,
1163
- self.name().clone(),
1164
- self.len(),
1165
- ))
312
+ fn apply_generic_with_dtype(
313
+ &self,
314
+ _rb: &Ruby,
315
+ _lambda: Value,
316
+ _datatype: &DataType,
317
+ _skip_nulls: bool,
318
+ ) -> RbResult<Series> {
319
+ unreachable!()
1166
320
  }
1167
321
  }