1use crate::array::{
21 ArrayAccessor, BooleanArray, FixedSizeBinaryArray, GenericBinaryArray, GenericListArray,
22 GenericStringArray, PrimitiveArray,
23};
24use crate::{FixedSizeListArray, GenericListViewArray, MapArray};
25use arrow_buffer::NullBuffer;
26
27#[derive(Debug)]
48pub struct ArrayIter<T: ArrayAccessor> {
49 array: T,
50 logical_nulls: Option<NullBuffer>,
51 current: usize,
52 current_end: usize,
53}
54
55impl<T: ArrayAccessor> ArrayIter<T> {
56 pub fn new(array: T) -> Self {
58 let len = array.len();
59 let logical_nulls = array.logical_nulls();
60 ArrayIter {
61 array,
62 logical_nulls,
63 current: 0,
64 current_end: len,
65 }
66 }
67
68 #[inline]
69 fn is_null(&self, idx: usize) -> bool {
70 self.logical_nulls
71 .as_ref()
72 .map(|x| x.is_null(idx))
73 .unwrap_or_default()
74 }
75}
76
77impl<T: ArrayAccessor> Iterator for ArrayIter<T> {
78 type Item = Option<T::Item>;
79
80 #[inline]
81 fn next(&mut self) -> Option<Self::Item> {
82 if self.current == self.current_end {
83 None
84 } else if self.is_null(self.current) {
85 self.current += 1;
86 Some(None)
87 } else {
88 let old = self.current;
89 self.current += 1;
90 unsafe { Some(Some(self.array.value_unchecked(old))) }
96 }
97 }
98
99 fn size_hint(&self) -> (usize, Option<usize>) {
100 (
101 self.array.len() - self.current,
102 Some(self.array.len() - self.current),
103 )
104 }
105}
106
107impl<T: ArrayAccessor> DoubleEndedIterator for ArrayIter<T> {
108 fn next_back(&mut self) -> Option<Self::Item> {
109 if self.current_end == self.current {
110 None
111 } else {
112 self.current_end -= 1;
113 Some(if self.is_null(self.current_end) {
114 None
115 } else {
116 unsafe { Some(self.array.value_unchecked(self.current_end)) }
122 })
123 }
124 }
125}
126
127impl<T: ArrayAccessor> ExactSizeIterator for ArrayIter<T> {}
129
130pub type PrimitiveIter<'a, T> = ArrayIter<&'a PrimitiveArray<T>>;
132pub type BooleanIter<'a> = ArrayIter<&'a BooleanArray>;
134pub type GenericStringIter<'a, T> = ArrayIter<&'a GenericStringArray<T>>;
136pub type GenericBinaryIter<'a, T> = ArrayIter<&'a GenericBinaryArray<T>>;
138pub type FixedSizeBinaryIter<'a> = ArrayIter<&'a FixedSizeBinaryArray>;
140pub type FixedSizeListIter<'a> = ArrayIter<&'a FixedSizeListArray>;
142pub type GenericListArrayIter<'a, O> = ArrayIter<&'a GenericListArray<O>>;
144pub type MapArrayIter<'a> = ArrayIter<&'a MapArray>;
146pub type GenericListViewArrayIter<'a, O> = ArrayIter<&'a GenericListViewArray<O>>;
148#[cfg(test)]
149mod tests {
150 use std::sync::Arc;
151
152 use crate::array::{ArrayRef, BinaryArray, BooleanArray, Int32Array, StringArray};
153
154 #[test]
155 fn test_primitive_array_iter_round_trip() {
156 let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
157 let array = Arc::new(array) as ArrayRef;
158
159 let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
160
161 let result: Int32Array = array.iter().map(|e| e.map(|e| e + 1)).collect();
163
164 let expected = Int32Array::from(vec![Some(1), None, Some(3), None, Some(5)]);
165 assert_eq!(result, expected);
166
167 let result: Int32Array = array.iter().rev().collect();
169 let rev_array = Int32Array::from(vec![Some(4), None, Some(2), None, Some(0)]);
170 assert_eq!(result, rev_array);
171 let _ = array.iter().rposition(|opt_b| opt_b == Some(1));
173 }
174
175 #[test]
176 fn test_double_ended() {
177 let array = Int32Array::from(vec![Some(0), None, Some(2), None, Some(4)]);
178 let mut a = array.iter();
179 assert_eq!(a.next(), Some(Some(0)));
180 assert_eq!(a.next(), Some(None));
181 assert_eq!(a.next_back(), Some(Some(4)));
182 assert_eq!(a.next_back(), Some(None));
183 assert_eq!(a.next_back(), Some(Some(2)));
184 assert_eq!(a.next_back(), None);
186 assert_eq!(a.next(), None);
187 }
188
189 #[test]
190 fn test_string_array_iter_round_trip() {
191 let array = StringArray::from(vec![Some("a"), None, Some("aaa"), None, Some("aaaaa")]);
192 let array = Arc::new(array) as ArrayRef;
193
194 let array = array.as_any().downcast_ref::<StringArray>().unwrap();
195
196 let result: StringArray = array
198 .iter()
199 .map(|e| {
200 e.map(|e| {
201 let mut a = e.to_string();
202 a.push('b');
203 a
204 })
205 })
206 .collect();
207
208 let expected =
209 StringArray::from(vec![Some("ab"), None, Some("aaab"), None, Some("aaaaab")]);
210 assert_eq!(result, expected);
211
212 let result: StringArray = array.iter().rev().collect();
214 let rev_array = StringArray::from(vec![Some("aaaaa"), None, Some("aaa"), None, Some("a")]);
215 assert_eq!(result, rev_array);
216 let _ = array.iter().rposition(|opt_b| opt_b == Some("a"));
218 }
219
220 #[test]
221 fn test_binary_array_iter_round_trip() {
222 let array = BinaryArray::from(vec![
223 Some(b"a" as &[u8]),
224 None,
225 Some(b"aaa"),
226 None,
227 Some(b"aaaaa"),
228 ]);
229
230 let result: BinaryArray = array.iter().collect();
232
233 assert_eq!(result, array);
234
235 let result: BinaryArray = array.iter().rev().collect();
237 let rev_array = BinaryArray::from(vec![
238 Some(b"aaaaa" as &[u8]),
239 None,
240 Some(b"aaa"),
241 None,
242 Some(b"a"),
243 ]);
244 assert_eq!(result, rev_array);
245
246 let _ = array.iter().rposition(|opt_b| opt_b == Some(&[9]));
248 }
249
250 #[test]
251 fn test_boolean_array_iter_round_trip() {
252 let array = BooleanArray::from(vec![Some(true), None, Some(false)]);
253
254 let result: BooleanArray = array.iter().collect();
256
257 assert_eq!(result, array);
258
259 let result: BooleanArray = array.iter().rev().collect();
261 let rev_array = BooleanArray::from(vec![Some(false), None, Some(true)]);
262 assert_eq!(result, rev_array);
263
264 let _ = array.iter().rposition(|opt_b| opt_b == Some(true));
266 }
267}