mod.rs - source (original) (raw)
polars_core/chunked_array/iterator/
mod.rs
1use arrow::array::*;
2
3use crate::prelude::*;
4
5pub mod par;
6
7impl<T> ChunkedArray<T>
8where
9 T: PolarsDataType,
10{
11 #[inline]
12 pub fn iter(&self) -> impl PolarsIterator<Item = Option<T::Physical<'_>>> {
13 // SAFETY: we set the correct length of the iterator.
14 unsafe {
15 self.downcast_iter()
16 .flat_map(|arr| arr.iter())
17 .trust_my_length(self.len())
18 }
19 }
20}
21
22/// A [`PolarsIterator`] is an iterator over a [`ChunkedArray`] which contains polars types. A [`PolarsIterator`]
23/// must implement [`ExactSizeIterator`] and [`DoubleEndedIterator`].
24pub trait PolarsIterator:
25 ExactSizeIterator + DoubleEndedIterator + Send + Sync + TrustedLen
26{
27}
28unsafe impl<I> TrustedLen for Box<dyn PolarsIterator<Item = I> + '_> {}
29
30/// Implement [`PolarsIterator`] for every iterator that implements the needed traits.
31impl<T: ?Sized> PolarsIterator for T where
32 T: ExactSizeIterator + DoubleEndedIterator + Send + Sync + TrustedLen
33{
34}
35
36impl<'a, T> IntoIterator for &'a ChunkedArray<T>
37where
38 T: PolarsNumericType,
39{
40 type Item = Option<T::Native>;
41 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
42 fn into_iter(self) -> Self::IntoIter {
43 Box::new(
44 // we know that we only iterate over length == self.len()
45 unsafe {
46 self.downcast_iter()
47 .flatten()
48 .map(|x| x.copied())
49 .trust_my_length(self.len())
50 },
51 )
52 }
53}
54
55impl<'a> IntoIterator for &'a BooleanChunked {
56 type Item = Option<bool>;
57 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
58 fn into_iter(self) -> Self::IntoIter {
59 // we know that we only iterate over length == self.len()
60 unsafe { Box::new(self.downcast_iter().flatten().trust_my_length(self.len())) }
61 }
62}
63
64/// The no null iterator for a [`BooleanArray`]
65pub struct BoolIterNoNull<'a> {
66 array: &'a BooleanArray,
67 current: usize,
68 current_end: usize,
69}
70
71impl<'a> BoolIterNoNull<'a> {
72 /// create a new iterator
73 pub fn new(array: &'a BooleanArray) -> Self {
74 BoolIterNoNull {
75 array,
76 current: 0,
77 current_end: array.len(),
78 }
79 }
80}
81
82impl Iterator for BoolIterNoNull<'_> {
83 type Item = bool;
84
85 fn next(&mut self) -> Option<Self::Item> {
86 if self.current == self.current_end {
87 None
88 } else {
89 let old = self.current;
90 self.current += 1;
91 unsafe { Some(self.array.value_unchecked(old)) }
92 }
93 }
94
95 fn size_hint(&self) -> (usize, Option<usize>) {
96 (
97 self.array.len() - self.current,
98 Some(self.array.len() - self.current),
99 )
100 }
101}
102
103impl DoubleEndedIterator for BoolIterNoNull<'_> {
104 fn next_back(&mut self) -> Option<Self::Item> {
105 if self.current_end == self.current {
106 None
107 } else {
108 self.current_end -= 1;
109 unsafe { Some(self.array.value_unchecked(self.current_end)) }
110 }
111 }
112}
113
114/// all arrays have known size.
115impl ExactSizeIterator for BoolIterNoNull<'_> {}
116
117impl BooleanChunked {
118 #[allow(clippy::wrong_self_convention)]
119 #[doc(hidden)]
120 pub fn into_no_null_iter(
121 &self,
122 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = bool> + DoubleEndedIterator + TrustedLen
123 {
124 // we know that we only iterate over length == self.len()
125 unsafe {
126 self.downcast_iter()
127 .flat_map(BoolIterNoNull::new)
128 .trust_my_length(self.len())
129 }
130 }
131}
132
133impl<'a> IntoIterator for &'a StringChunked {
134 type Item = Option<&'a str>;
135 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
136 fn into_iter(self) -> Self::IntoIter {
137 // we know that we only iterate over length == self.len()
138 unsafe { Box::new(self.downcast_iter().flatten().trust_my_length(self.len())) }
139 }
140}
141
142impl StringChunked {
143 #[allow(clippy::wrong_self_convention)]
144 #[doc(hidden)]
145 pub fn into_no_null_iter(
146 &self,
147 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = &str> + DoubleEndedIterator + TrustedLen
148 {
149 // we know that we only iterate over length == self.len()
150 unsafe {
151 self.downcast_iter()
152 .flat_map(|arr| arr.values_iter())
153 .trust_my_length(self.len())
154 }
155 }
156}
157
158impl<'a> IntoIterator for &'a BinaryChunked {
159 type Item = Option<&'a [u8]>;
160 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
161 fn into_iter(self) -> Self::IntoIter {
162 // we know that we only iterate over length == self.len()
163 unsafe { Box::new(self.downcast_iter().flatten().trust_my_length(self.len())) }
164 }
165}
166
167impl BinaryChunked {
168 #[allow(clippy::wrong_self_convention)]
169 #[doc(hidden)]
170 pub fn into_no_null_iter(
171 &self,
172 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = &[u8]> + DoubleEndedIterator + TrustedLen
173 {
174 // we know that we only iterate over length == self.len()
175 unsafe {
176 self.downcast_iter()
177 .flat_map(|arr| arr.values_iter())
178 .trust_my_length(self.len())
179 }
180 }
181}
182
183impl<'a> IntoIterator for &'a BinaryOffsetChunked {
184 type Item = Option<&'a [u8]>;
185 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
186 fn into_iter(self) -> Self::IntoIter {
187 // we know that we only iterate over length == self.len()
188 unsafe { Box::new(self.downcast_iter().flatten().trust_my_length(self.len())) }
189 }
190}
191
192impl BinaryOffsetChunked {
193 #[allow(clippy::wrong_self_convention)]
194 #[doc(hidden)]
195 pub fn into_no_null_iter(
196 &self,
197 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = &[u8]> + DoubleEndedIterator + TrustedLen
198 {
199 // we know that we only iterate over length == self.len()
200 unsafe {
201 self.downcast_iter()
202 .flat_map(|arr| arr.values_iter())
203 .trust_my_length(self.len())
204 }
205 }
206}
207
208impl<'a> IntoIterator for &'a ListChunked {
209 type Item = Option<Series>;
210 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
211 fn into_iter(self) -> Self::IntoIter {
212 let dtype = self.inner_dtype();
213
214 if self.null_count() == 0 {
215 // we know that we only iterate over length == self.len()
216 unsafe {
217 Box::new(
218 self.downcast_iter()
219 .flat_map(|arr| arr.iter().unwrap_required())
220 .trust_my_length(self.len())
221 .map(move |arr| {
222 Some(Series::from_chunks_and_dtype_unchecked(
223 PlSmallStr::EMPTY,
224 vec![arr],
225 dtype,
226 ))
227 }),
228 )
229 }
230 } else {
231 // we know that we only iterate over length == self.len()
232 unsafe {
233 Box::new(
234 self.downcast_iter()
235 .flat_map(|arr| arr.iter())
236 .trust_my_length(self.len())
237 .map(move |arr| {
238 arr.map(|arr| {
239 Series::from_chunks_and_dtype_unchecked(
240 PlSmallStr::EMPTY,
241 vec![arr],
242 dtype,
243 )
244 })
245 }),
246 )
247 }
248 }
249 }
250}
251
252impl ListChunked {
253 #[allow(clippy::wrong_self_convention)]
254 #[doc(hidden)]
255 pub fn into_no_null_iter(
256 &self,
257 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = Series> + DoubleEndedIterator + TrustedLen
258 {
259 let inner_type = self.inner_dtype();
260 unsafe {
261 self.downcast_iter()
262 .flat_map(|arr| arr.values_iter())
263 .map(move |arr| {
264 Series::from_chunks_and_dtype_unchecked(
265 PlSmallStr::EMPTY,
266 vec![arr],
267 inner_type,
268 )
269 })
270 .trust_my_length(self.len())
271 }
272 }
273}
274
275#[cfg(feature = "dtype-array")]
276impl<'a> IntoIterator for &'a ArrayChunked {
277 type Item = Option<Series>;
278 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
279 fn into_iter(self) -> Self::IntoIter {
280 let dtype = self.inner_dtype();
281
282 if self.null_count() == 0 {
283 // we know that we only iterate over length == self.len()
284 unsafe {
285 Box::new(
286 self.downcast_iter()
287 .flat_map(|arr| arr.iter().unwrap_required())
288 .trust_my_length(self.len())
289 .map(move |arr| {
290 Some(Series::from_chunks_and_dtype_unchecked(
291 PlSmallStr::EMPTY,
292 vec![arr],
293 dtype,
294 ))
295 }),
296 )
297 }
298 } else {
299 // we know that we only iterate over length == self.len()
300 unsafe {
301 Box::new(
302 self.downcast_iter()
303 .flat_map(|arr| arr.iter())
304 .trust_my_length(self.len())
305 .map(move |arr| {
306 arr.map(|arr| {
307 Series::from_chunks_and_dtype_unchecked(
308 PlSmallStr::EMPTY,
309 vec![arr],
310 dtype,
311 )
312 })
313 }),
314 )
315 }
316 }
317 }
318}
319
320#[cfg(feature = "dtype-array")]
321pub struct FixedSizeListIterNoNull<'a> {
322 array: &'a FixedSizeListArray,
323 inner_type: DataType,
324 current: usize,
325 current_end: usize,
326}
327
328#[cfg(feature = "dtype-array")]
329impl<'a> FixedSizeListIterNoNull<'a> {
330 /// create a new iterator
331 pub fn new(array: &'a FixedSizeListArray, inner_type: DataType) -> Self {
332 FixedSizeListIterNoNull {
333 array,
334 inner_type,
335 current: 0,
336 current_end: array.len(),
337 }
338 }
339}
340
341#[cfg(feature = "dtype-array")]
342impl Iterator for FixedSizeListIterNoNull<'_> {
343 type Item = Series;
344
345 fn next(&mut self) -> Option<Self::Item> {
346 if self.current == self.current_end {
347 None
348 } else {
349 let old = self.current;
350 self.current += 1;
351 unsafe {
352 Some(Series::from_chunks_and_dtype_unchecked(
353 PlSmallStr::EMPTY,
354 vec![self.array.value_unchecked(old)],
355 &self.inner_type,
356 ))
357 }
358 }
359 }
360
361 fn size_hint(&self) -> (usize, Option<usize>) {
362 (
363 self.array.len() - self.current,
364 Some(self.array.len() - self.current),
365 )
366 }
367}
368
369#[cfg(feature = "dtype-array")]
370impl DoubleEndedIterator for FixedSizeListIterNoNull<'_> {
371 fn next_back(&mut self) -> Option<Self::Item> {
372 if self.current_end == self.current {
373 None
374 } else {
375 self.current_end -= 1;
376 unsafe {
377 Some(
378 Series::try_from((
379 PlSmallStr::EMPTY,
380 self.array.value_unchecked(self.current_end),
381 ))
382 .unwrap(),
383 )
384 }
385 }
386 }
387}
388
389/// all arrays have known size.
390#[cfg(feature = "dtype-array")]
391impl ExactSizeIterator for FixedSizeListIterNoNull<'_> {}
392
393#[cfg(feature = "dtype-array")]
394impl ArrayChunked {
395 #[allow(clippy::wrong_self_convention)]
396 #[doc(hidden)]
397 pub fn into_no_null_iter(
398 &self,
399 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = Series> + DoubleEndedIterator + TrustedLen
400 {
401 // we know that we only iterate over length == self.len()
402 let inner_type = self.inner_dtype();
403 unsafe {
404 self.downcast_iter()
405 .flat_map(move |arr| FixedSizeListIterNoNull::new(arr, inner_type.clone()))
406 .trust_my_length(self.len())
407 }
408 }
409}
410
411#[cfg(feature = "object")]
412impl<'a, T> IntoIterator for &'a ObjectChunked<T>
413where
414 T: PolarsObject,
415{
416 type Item = Option<&'a T>;
417 type IntoIter = Box<dyn PolarsIterator<Item = Self::Item> + 'a>;
418 fn into_iter(self) -> Self::IntoIter {
419 // we know that we only iterate over length == self.len()
420 unsafe { Box::new(self.downcast_iter().flatten().trust_my_length(self.len())) }
421 }
422}
423
424#[cfg(feature = "object")]
425impl<T: PolarsObject> ObjectChunked<T> {
426 #[allow(clippy::wrong_self_convention)]
427 #[doc(hidden)]
428 pub fn into_no_null_iter(
429 &self,
430 ) -> impl '_ + Send + Sync + ExactSizeIterator<Item = &T> + DoubleEndedIterator + TrustedLen
431 {
432 // we know that we only iterate over length == self.len()
433 unsafe {
434 self.downcast_iter()
435 .flat_map(|arr| arr.values_iter())
436 .trust_my_length(self.len())
437 }
438 }
439}
440
441/// Wrapper struct to convert an iterator of type `T` into one of type [`Option<T>`]. It is useful to make the
442/// [`IntoIterator`] trait, in which every iterator shall return an [`Option<T>`].
443pub struct SomeIterator<I>(I)
444where
445 I: Iterator;
446
447impl<I> Iterator for SomeIterator<I>
448where
449 I: Iterator,
450{
451 type Item = Option<I::Item>;
452
453 fn next(&mut self) -> Option<Self::Item> {
454 self.0.next().map(Some)
455 }
456
457 fn size_hint(&self) -> (usize, Option<usize>) {
458 self.0.size_hint()
459 }
460}
461
462impl<I> DoubleEndedIterator for SomeIterator<I>
463where
464 I: DoubleEndedIterator,
465{
466 fn next_back(&mut self) -> Option<Self::Item> {
467 self.0.next_back().map(Some)
468 }
469}
470
471impl<I> ExactSizeIterator for SomeIterator<I> where I: ExactSizeIterator {}
472
473#[cfg(test)]
474mod test {
475 use crate::prelude::*;
476
477 #[test]
478 fn out_of_bounds() {
479 let mut a = UInt32Chunked::from_slice(PlSmallStr::from_static("a"), &[1, 2, 3]);
480 let b = UInt32Chunked::from_slice(PlSmallStr::from_static("a"), &[1, 2, 3]);
481 a.append(&b).unwrap();
482
483 let v = a.into_iter().collect::<Vec<_>>();
484 assert_eq!(
485 vec![Some(1u32), Some(2), Some(3), Some(1), Some(2), Some(3)],
486 v
487 )
488 }
489
490 /// Generate test for [`IntoIterator`] trait for chunked arrays with just one chunk and no null values.
491 /// The expected return value of the iterator generated by [`IntoIterator`] trait is [`Option<T>`], where
492 /// `T` is the chunked array type.
493 ///
494 /// # Input
495 ///
496 /// test_name: The name of the test to generate.
497 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
498 /// first_val: The first value contained in the chunked array.
499 /// second_val: The second value contained in the chunked array.
500 /// third_val: The third value contained in the chunked array.
501 macro_rules! impl_test_iter_single_chunk {
502 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
503 #[test]
504 fn $test_name() {
505 let a = <$ca_type>::from_slice(
506 PlSmallStr::from_static("test"),
507 &[$first_val, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mpunct">,</span></span></span></span>third_val],
508 );
509
510 // normal iterator
511 let mut it = a.into_iter();
512 assert_eq!(it.next(), Some(Some($first_val)));
513 assert_eq!(it.next(), Some(Some($second_val)));
514 assert_eq!(it.next(), Some(Some($third_val)));
515 assert_eq!(it.next(), None);
516 // ensure both sides are consumes.
517 assert_eq!(it.next_back(), None);
518
519 // reverse iterator
520 let mut it = a.into_iter();
521 assert_eq!(it.next_back(), Some(Some($third_val)));
522 assert_eq!(it.next_back(), Some(Some($second_val)));
523 assert_eq!(it.next_back(), Some(Some($first_val)));
524 assert_eq!(it.next_back(), None);
525 // ensure both sides are consumes.
526 assert_eq!(it.next(), None);
527
528 // iterators should not cross
529 let mut it = a.into_iter();
530 assert_eq!(it.next_back(), Some(Some($third_val)));
531 assert_eq!(it.next(), Some(Some($first_val)));
532 assert_eq!(it.next(), Some(Some($second_val)));
533 // should stop here as we took this one from the back
534 assert_eq!(it.next(), None);
535 // ensure both sides are consumes.
536 assert_eq!(it.next_back(), None);
537
538 // do the same from the right side
539 let mut it = a.into_iter();
540 assert_eq!(it.next(), Some(Some($first_val)));
541 assert_eq!(it.next_back(), Some(Some($third_val)));
542 assert_eq!(it.next_back(), Some(Some($second_val)));
543 assert_eq!(it.next_back(), None);
544 // ensure both sides are consumes.
545 assert_eq!(it.next(), None);
546 }
547 };
548 }
549
550 impl_test_iter_single_chunk!(num_iter_single_chunk, UInt32Chunked, 1, 2, 3);
551 impl_test_iter_single_chunk!(utf8_iter_single_chunk, StringChunked, "a", "b", "c");
552 impl_test_iter_single_chunk!(bool_iter_single_chunk, BooleanChunked, true, true, false);
553
554 /// Generate test for [`IntoIterator`] trait for chunked arrays with just one chunk and null values.
555 /// The expected return value of the iterator generated by [`IntoIterator`] trait is [`Option<T>`], where
556 /// `T` is the chunked array type.
557 ///
558 /// # Input
559 ///
560 /// test_name: The name of the test to generate.
561 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
562 /// first_val: The first value contained in the chunked array. Must be an [`Option<T>`].
563 /// second_val: The second value contained in the chunked array. Must be an [`Option<T>`].
564 /// third_val: The third value contained in the chunked array. Must be an [`Option<T>`].
565 macro_rules! impl_test_iter_single_chunk_null_check {
566 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
567 #[test]
568 fn $test_name() {
569 let a = <$ca_type>::new(
570 PlSmallStr::from_static("test"),
571 &[$first_val, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mpunct">,</span></span></span></span>third_val],
572 );
573
574 // normal iterator
575 let mut it = a.into_iter();
576 assert_eq!(it.next(), Some($first_val));
577 assert_eq!(it.next(), Some($second_val));
578 assert_eq!(it.next(), Some($third_val));
579 assert_eq!(it.next(), None);
580 // ensure both sides are consumes.
581 assert_eq!(it.next_back(), None);
582
583 // reverse iterator
584 let mut it = a.into_iter();
585 assert_eq!(it.next_back(), Some($third_val));
586 assert_eq!(it.next_back(), Some($second_val));
587 assert_eq!(it.next_back(), Some($first_val));
588 assert_eq!(it.next_back(), None);
589 // ensure both sides are consumes.
590 assert_eq!(it.next(), None);
591
592 // iterators should not cross
593 let mut it = a.into_iter();
594 assert_eq!(it.next_back(), Some($third_val));
595 assert_eq!(it.next(), Some($first_val));
596 assert_eq!(it.next(), Some($second_val));
597 // should stop here as we took this one from the back
598 assert_eq!(it.next(), None);
599 // ensure both sides are consumes.
600 assert_eq!(it.next_back(), None);
601
602 // do the same from the right side
603 let mut it = a.into_iter();
604 assert_eq!(it.next(), Some($first_val));
605 assert_eq!(it.next_back(), Some($third_val));
606 assert_eq!(it.next_back(), Some($second_val));
607 assert_eq!(it.next_back(), None);
608 // ensure both sides are consumes.
609 assert_eq!(it.next(), None);
610 }
611 };
612 }
613
614 impl_test_iter_single_chunk_null_check!(
615 num_iter_single_chunk_null_check,
616 UInt32Chunked,
617 Some(1),
618 None,
619 Some(3)
620 );
621 impl_test_iter_single_chunk_null_check!(
622 utf8_iter_single_chunk_null_check,
623 StringChunked,
624 Some("a"),
625 None,
626 Some("c")
627 );
628 impl_test_iter_single_chunk_null_check!(
629 bool_iter_single_chunk_null_check,
630 BooleanChunked,
631 Some(true),
632 None,
633 Some(false)
634 );
635
636 /// Generate test for [`IntoIterator`] trait for chunked arrays with many chunks and no null values.
637 /// The expected return value of the iterator generated by [`IntoIterator`] trait is [`Option<T>`], where
638 /// `T` is the chunked array type.
639 ///
640 /// # Input
641 ///
642 /// test_name: The name of the test to generate.
643 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
644 /// first_val: The first value contained in the chunked array.
645 /// second_val: The second value contained in the chunked array.
646 /// third_val: The third value contained in the chunked array.
647 macro_rules! impl_test_iter_many_chunk {
648 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
649 #[test]
650 fn $test_name() {
651 let mut a = <$ca_type>::from_slice(
652 PlSmallStr::from_static("test"),
653 &[$first_val, $second_val],
654 );
655 let a_b = <$ca_type>::from_slice(PlSmallStr::EMPTY, &[$third_val]);
656 a.append(&a_b).unwrap();
657
658 // normal iterator
659 let mut it = a.into_iter();
660 assert_eq!(it.next(), Some(Some($first_val)));
661 assert_eq!(it.next(), Some(Some($second_val)));
662 assert_eq!(it.next(), Some(Some($third_val)));
663 assert_eq!(it.next(), None);
664 // ensure both sides are consumes.
665 assert_eq!(it.next_back(), None);
666
667 // reverse iterator
668 let mut it = a.into_iter();
669 assert_eq!(it.next_back(), Some(Some($third_val)));
670 assert_eq!(it.next_back(), Some(Some($second_val)));
671 assert_eq!(it.next_back(), Some(Some($first_val)));
672 assert_eq!(it.next_back(), None);
673 // ensure both sides are consumes.
674 assert_eq!(it.next(), None);
675
676 // iterators should not cross
677 let mut it = a.into_iter();
678 assert_eq!(it.next_back(), Some(Some($third_val)));
679 assert_eq!(it.next(), Some(Some($first_val)));
680 assert_eq!(it.next(), Some(Some($second_val)));
681 // should stop here as we took this one from the back
682 assert_eq!(it.next(), None);
683 // ensure both sides are consumes.
684 assert_eq!(it.next_back(), None);
685
686 // do the same from the right side
687 let mut it = a.into_iter();
688 assert_eq!(it.next(), Some(Some($first_val)));
689 assert_eq!(it.next_back(), Some(Some($third_val)));
690 assert_eq!(it.next_back(), Some(Some($second_val)));
691 assert_eq!(it.next_back(), None);
692 // ensure both sides are consumes.
693 assert_eq!(it.next(), None);
694 }
695 };
696 }
697
698 impl_test_iter_many_chunk!(num_iter_many_chunk, UInt32Chunked, 1, 2, 3);
699 impl_test_iter_many_chunk!(utf8_iter_many_chunk, StringChunked, "a", "b", "c");
700 impl_test_iter_many_chunk!(bool_iter_many_chunk, BooleanChunked, true, true, false);
701
702 /// Generate test for [`IntoIterator`] trait for chunked arrays with many chunk and null values.
703 /// The expected return value of the iterator generated by [`IntoIterator`] trait is [`Option<T>`], where
704 /// `T` is the chunked array type.
705 ///
706 /// # Input
707 ///
708 /// test_name: The name of the test to generate.
709 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
710 /// first_val: The first value contained in the chunked array. Must be an [`Option<T>`].
711 /// second_val: The second value contained in the chunked array. Must be an [`Option<T>`].
712 /// third_val: The third value contained in the chunked array. Must be an [`Option<T>`].
713 macro_rules! impl_test_iter_many_chunk_null_check {
714 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
715 #[test]
716 fn $test_name() {
717 let mut a =
718 <$ca_type>::new(PlSmallStr::from_static("test"), &[$first_val, $second_val]);
719 let a_b = <$ca_type>::new(PlSmallStr::EMPTY, &[$third_val]);
720 a.append(&a_b).unwrap();
721
722 // normal iterator
723 let mut it = a.into_iter();
724 assert_eq!(it.next(), Some($first_val));
725 assert_eq!(it.next(), Some($second_val));
726 assert_eq!(it.next(), Some($third_val));
727 assert_eq!(it.next(), None);
728 // ensure both sides are consumes.
729 assert_eq!(it.next_back(), None);
730
731 // reverse iterator
732 let mut it = a.into_iter();
733 assert_eq!(it.next_back(), Some($third_val));
734 assert_eq!(it.next_back(), Some($second_val));
735 assert_eq!(it.next_back(), Some($first_val));
736 assert_eq!(it.next_back(), None);
737 // ensure both sides are consumes.
738 assert_eq!(it.next(), None);
739
740 // iterators should not cross
741 let mut it = a.into_iter();
742 assert_eq!(it.next_back(), Some($third_val));
743 assert_eq!(it.next(), Some($first_val));
744 assert_eq!(it.next(), Some($second_val));
745 // should stop here as we took this one from the back
746 assert_eq!(it.next(), None);
747 // ensure both sides are consumes.
748 assert_eq!(it.next_back(), None);
749
750 // do the same from the right side
751 let mut it = a.into_iter();
752 assert_eq!(it.next(), Some($first_val));
753 assert_eq!(it.next_back(), Some($third_val));
754 assert_eq!(it.next_back(), Some($second_val));
755 assert_eq!(it.next_back(), None);
756 // ensure both sides are consumes.
757 assert_eq!(it.next(), None);
758 }
759 };
760 }
761
762 impl_test_iter_many_chunk_null_check!(
763 num_iter_many_chunk_null_check,
764 UInt32Chunked,
765 Some(1),
766 None,
767 Some(3)
768 );
769 impl_test_iter_many_chunk_null_check!(
770 utf8_iter_many_chunk_null_check,
771 StringChunked,
772 Some("a"),
773 None,
774 Some("c")
775 );
776 impl_test_iter_many_chunk_null_check!(
777 bool_iter_many_chunk_null_check,
778 BooleanChunked,
779 Some(true),
780 None,
781 Some(false)
782 );
783
784 /// Generate test for [`IntoNoNullIterator`] trait for chunked arrays with just one chunk and no null values.
785 /// The expected return value of the iterator generated by [`IntoNoNullIterator`] trait is `T`, where
786 /// `T` is the chunked array type.
787 ///
788 /// # Input
789 ///
790 /// test_name: The name of the test to generate.
791 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
792 /// first_val: The first value contained in the chunked array.
793 /// second_val: The second value contained in the chunked array.
794 /// third_val: The third value contained in the chunked array.
795 macro_rules! impl_test_no_null_iter_single_chunk {
796 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
797 #[test]
798 fn $test_name() {
799 let a = <$ca_type>::from_slice(
800 PlSmallStr::from_static("test"),
801 &[$first_val, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mpunct">,</span></span></span></span>third_val],
802 );
803
804 // normal iterator
805 let mut it = a.into_no_null_iter();
806 assert_eq!(it.next(), Some($first_val));
807 assert_eq!(it.next(), Some($second_val));
808 assert_eq!(it.next(), Some($third_val));
809 assert_eq!(it.next(), None);
810 // ensure both sides are consumes.
811 assert_eq!(it.next_back(), None);
812
813 // reverse iterator
814 let mut it = a.into_no_null_iter();
815 assert_eq!(it.next_back(), Some($third_val));
816 assert_eq!(it.next_back(), Some($second_val));
817 assert_eq!(it.next_back(), Some($first_val));
818 assert_eq!(it.next_back(), None);
819 // ensure both sides are consumes.
820 assert_eq!(it.next(), None);
821
822 // iterators should not cross
823 let mut it = a.into_no_null_iter();
824 assert_eq!(it.next_back(), Some($third_val));
825 assert_eq!(it.next(), Some($first_val));
826 assert_eq!(it.next(), Some($second_val));
827 // should stop here as we took this one from the back
828 assert_eq!(it.next(), None);
829 // ensure both sides are consumes.
830 assert_eq!(it.next_back(), None);
831
832 // do the same from the right side
833 let mut it = a.into_no_null_iter();
834 assert_eq!(it.next(), Some($first_val));
835 assert_eq!(it.next_back(), Some($third_val));
836 assert_eq!(it.next_back(), Some($second_val));
837 assert_eq!(it.next_back(), None);
838 // ensure both sides are consumes.
839 assert_eq!(it.next(), None);
840 }
841 };
842 }
843
844 impl_test_no_null_iter_single_chunk!(num_no_null_iter_single_chunk, UInt32Chunked, 1, 2, 3);
845 impl_test_no_null_iter_single_chunk!(
846 utf8_no_null_iter_single_chunk,
847 StringChunked,
848 "a",
849 "b",
850 "c"
851 );
852 impl_test_no_null_iter_single_chunk!(
853 bool_no_null_iter_single_chunk,
854 BooleanChunked,
855 true,
856 true,
857 false
858 );
859
860 /// Generate test for [`IntoNoNullIterator`] trait for chunked arrays with many chunks and no null values.
861 /// The expected return value of the iterator generated by [`IntoNoNullIterator`] trait is `T`, where
862 /// `T` is the chunked array type.
863 ///
864 /// # Input
865 ///
866 /// test_name: The name of the test to generate.
867 /// ca_type: The chunked array to use for this test. Ex: [`StringChunked`], [`UInt32Chunked`] ...
868 /// first_val: The first value contained in the chunked array.
869 /// second_val: The second value contained in the chunked array.
870 /// third_val: The third value contained in the chunked array.
871 macro_rules! impl_test_no_null_iter_many_chunk {
872 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>c</mi><msub><mi>a</mi><mi>t</mi></msub><mi>y</mi><mi>p</mi><mi>e</mi><mo>:</mo><mi>t</mi><mi>y</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">ca_type:ty, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">c</span><span class="mord"><span class="mord mathnormal">a</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.2806em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight">t</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mord mathnormal">p</span><span class="mord mathnormal">e</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.8095em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">t</span><span class="mord mathnormal" style="margin-right:0.03588em;">y</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>third_val:expr) => {
873 #[test]
874 fn $test_name() {
875 let mut a = <$ca_type>::from_slice(
876 PlSmallStr::from_static("test"),
877 &[$first_val, $second_val],
878 );
879 let a_b = <$ca_type>::from_slice(PlSmallStr::EMPTY, &[$third_val]);
880 a.append(&a_b).unwrap();
881
882 // normal iterator
883 let mut it = a.into_no_null_iter();
884 assert_eq!(it.next(), Some($first_val));
885 assert_eq!(it.next(), Some($second_val));
886 assert_eq!(it.next(), Some($third_val));
887 assert_eq!(it.next(), None);
888 // ensure both sides are consumes.
889 assert_eq!(it.next_back(), None);
890
891 // reverse iterator
892 let mut it = a.into_no_null_iter();
893 assert_eq!(it.next_back(), Some($third_val));
894 assert_eq!(it.next_back(), Some($second_val));
895 assert_eq!(it.next_back(), Some($first_val));
896 assert_eq!(it.next_back(), None);
897 // ensure both sides are consumes.
898 assert_eq!(it.next(), None);
899
900 // iterators should not cross
901 let mut it = a.into_no_null_iter();
902 assert_eq!(it.next_back(), Some($third_val));
903 assert_eq!(it.next(), Some($first_val));
904 assert_eq!(it.next(), Some($second_val));
905 // should stop here as we took this one from the back
906 assert_eq!(it.next(), None);
907 // ensure both sides are consumes.
908 assert_eq!(it.next_back(), None);
909
910 // do the same from the right side
911 let mut it = a.into_no_null_iter();
912 assert_eq!(it.next(), Some($first_val));
913 assert_eq!(it.next_back(), Some($third_val));
914 assert_eq!(it.next_back(), Some($second_val));
915 assert_eq!(it.next_back(), None);
916 // ensure both sides are consumes.
917 assert_eq!(it.next(), None);
918 }
919 };
920 }
921
922 impl_test_no_null_iter_many_chunk!(num_no_null_iter_many_chunk, UInt32Chunked, 1, 2, 3);
923 impl_test_no_null_iter_many_chunk!(utf8_no_null_iter_many_chunk, StringChunked, "a", "b", "c");
924 impl_test_no_null_iter_many_chunk!(
925 bool_no_null_iter_many_chunk,
926 BooleanChunked,
927 true,
928 true,
929 false
930 );
931
932 /// The size of the skip iterator.
933 const SKIP_ITERATOR_SIZE: usize = 10;
934
935 /// Generates tests to verify the correctness of the `skip` method.
936 ///
937 /// # Input
938 ///
939 /// test_name: The name of the test to implement, it is a function name so it shall be unique.
940 /// skip_values: The number of values to skip. Keep in mind that is the number of values to skip
941 /// after performing the first next, then, skip_values = 8, will skip until index 1 + skip_values = 9.
942 /// first_val: The value before skip.
943 /// second_val: The value after skip.
944 /// ca_init_block: The block which initialize the chunked array. It shall return the chunked array.
945 macro_rules! impl_test_iter_skip {
946 ($test_name:ident, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>k</mi><mi>i</mi><msub><mi>p</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mi>u</mi><mi>e</mi><mi>s</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">skip_values:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8889em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">s</span><span class="mord mathnormal">ki</span><span class="mord"><span class="mord mathnormal">p</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mord mathnormal">u</span><span class="mord mathnormal">es</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>first_val:expr, <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mi>s</mi><mi>e</mi><mi>c</mi><mi>o</mi><mi>n</mi><msub><mi>d</mi><mi>v</mi></msub><mi>a</mi><mi>l</mi><mo>:</mo><mi>e</mi><mi>x</mi><mi>p</mi><mi>r</mi><mo separator="true">,</mo></mrow><annotation encoding="application/x-tex">second_val:expr, </annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:0.8444em;vertical-align:-0.15em;"></span><span class="mord mathnormal">seco</span><span class="mord mathnormal">n</span><span class="mord"><span class="mord mathnormal">d</span><span class="msupsub"><span class="vlist-t vlist-t2"><span class="vlist-r"><span class="vlist" style="height:0.1514em;"><span style="top:-2.55em;margin-left:0em;margin-right:0.05em;"><span class="pstrut" style="height:2.7em;"></span><span class="sizing reset-size6 size3 mtight"><span class="mord mathnormal mtight" style="margin-right:0.03588em;">v</span></span></span></span><span class="vlist-s"></span></span><span class="vlist-r"><span class="vlist" style="height:0.15em;"><span></span></span></span></span></span></span><span class="mord mathnormal">a</span><span class="mord mathnormal" style="margin-right:0.01968em;">l</span><span class="mspace" style="margin-right:0.2778em;"></span><span class="mrel">:</span><span class="mspace" style="margin-right:0.2778em;"></span></span><span class="base"><span class="strut" style="height:0.625em;vertical-align:-0.1944em;"></span><span class="mord mathnormal">e</span><span class="mord mathnormal">x</span><span class="mord mathnormal">p</span><span class="mord mathnormal" style="margin-right:0.02778em;">r</span><span class="mpunct">,</span></span></span></span>ca_init_block:block) => {
947 #[test]
948 fn $test_name() {
949 let a = $ca_init_block;
950
951 // Consume first position of iterator.
952 let mut it = a.into_iter();
953 assert_eq!(it.next(), Some($first_val));
954
955 // Consume `$skip_values` and check the result.
956 let mut it = it.skip($skip_values);
957 assert_eq!(it.next(), Some($second_val));
958
959 // Consume more values than available and check result is None.
960 let mut it = it.skip(SKIP_ITERATOR_SIZE);
961 assert_eq!(it.next(), None);
962 }
963 };
964 }
965
966 /// Generates a `Vec` of `Strings`, where every position is the `String` representation of its index.
967 fn generate_utf8_vec(size: usize) -> Vec<String> {
968 (0..size).map(|n| n.to_string()).collect()
969 }
970
971 /// Generate a `Vec` of `Option<String>`, where even indexes are `Some("{idx}")` and odd indexes are `None`.
972 fn generate_opt_utf8_vec(size: usize) -> Vec<Option<String>> {
973 (0..size)
974 .map(|n| {
975 if n % 2 == 0 {
976 Some(n.to_string())
977 } else {
978 None
979 }
980 })
981 .collect()
982 }
983
984 impl_test_iter_skip!(utf8_iter_single_chunk_skip, 8, Some("0"), Some("9"), {
985 StringChunked::from_slice(
986 PlSmallStr::from_static("test"),
987 &generate_utf8_vec(SKIP_ITERATOR_SIZE),
988 )
989 });
990
991 impl_test_iter_skip!(
992 utf8_iter_single_chunk_null_check_skip,
993 8,
994 Some("0"),
995 None,
996 {
997 StringChunked::new(
998 PlSmallStr::from_static("test"),
999 &generate_opt_utf8_vec(SKIP_ITERATOR_SIZE),
1000 )
1001 }
1002 );
1003
1004 impl_test_iter_skip!(utf8_iter_many_chunk_skip, 18, Some("0"), Some("9"), {
1005 let mut a = StringChunked::from_slice(
1006 PlSmallStr::from_static("test"),
1007 &generate_utf8_vec(SKIP_ITERATOR_SIZE),
1008 );
1009 let a_b = StringChunked::from_slice(
1010 PlSmallStr::from_static("test"),
1011 &generate_utf8_vec(SKIP_ITERATOR_SIZE),
1012 );
1013 a.append(&a_b).unwrap();
1014 a
1015 });
1016
1017 impl_test_iter_skip!(utf8_iter_many_chunk_null_check_skip, 18, Some("0"), None, {
1018 let mut a = StringChunked::new(
1019 PlSmallStr::from_static("test"),
1020 &generate_opt_utf8_vec(SKIP_ITERATOR_SIZE),
1021 );
1022 let a_b = StringChunked::new(
1023 PlSmallStr::from_static("test"),
1024 &generate_opt_utf8_vec(SKIP_ITERATOR_SIZE),
1025 );
1026 a.append(&a_b).unwrap();
1027 a
1028 });
1029
1030 /// Generates a [`Vec`] of [`bool`], with even indexes are true, and odd indexes are false.
1031 fn generate_boolean_vec(size: usize) -> Vec<bool> {
1032 (0..size).map(|n| n % 2 == 0).collect()
1033 }
1034
1035 /// Generate a [`Vec`] of [`Option<bool>`], where:
1036 /// - If the index is divisible by 3, then, the value is `None`.
1037 /// - If the index is not divisible by 3 and it is even, then, the value is `Some(true)`.
1038 /// - Otherwise, the value is `Some(false)`.
1039 fn generate_opt_boolean_vec(size: usize) -> Vec<Option<bool>> {
1040 (0..size)
1041 .map(|n| if n % 3 == 0 { None } else { Some(n % 2 == 0) })
1042 .collect()
1043 }
1044
1045 impl_test_iter_skip!(bool_iter_single_chunk_skip, 8, Some(true), Some(false), {
1046 BooleanChunked::from_slice(
1047 PlSmallStr::from_static("test"),
1048 &generate_boolean_vec(SKIP_ITERATOR_SIZE),
1049 )
1050 });
1051
1052 impl_test_iter_skip!(bool_iter_single_chunk_null_check_skip, 8, None, None, {
1053 BooleanChunked::new(
1054 PlSmallStr::from_static("test"),
1055 &generate_opt_boolean_vec(SKIP_ITERATOR_SIZE),
1056 )
1057 });
1058
1059 impl_test_iter_skip!(bool_iter_many_chunk_skip, 18, Some(true), Some(false), {
1060 let mut a = BooleanChunked::from_slice(
1061 PlSmallStr::from_static("test"),
1062 &generate_boolean_vec(SKIP_ITERATOR_SIZE),
1063 );
1064 let a_b = BooleanChunked::from_slice(
1065 PlSmallStr::from_static("test"),
1066 &generate_boolean_vec(SKIP_ITERATOR_SIZE),
1067 );
1068 a.append(&a_b).unwrap();
1069 a
1070 });
1071
1072 impl_test_iter_skip!(bool_iter_many_chunk_null_check_skip, 18, None, None, {
1073 let mut a = BooleanChunked::new(
1074 PlSmallStr::from_static("test"),
1075 &generate_opt_boolean_vec(SKIP_ITERATOR_SIZE),
1076 );
1077 let a_b = BooleanChunked::new(
1078 PlSmallStr::from_static("test"),
1079 &generate_opt_boolean_vec(SKIP_ITERATOR_SIZE),
1080 );
1081 a.append(&a_b).unwrap();
1082 a
1083 });
1084}