Skip to content

Commit 3c5bcd4

Browse files
Make VariantArray iterable
1 parent 77ca6dc commit 3c5bcd4

File tree

1 file changed

+175
-0
lines changed

1 file changed

+175
-0
lines changed

parquet-variant-compute/src/variant_array.rs

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,11 @@ impl VariantArray {
422422
pub fn is_valid(&self, index: usize) -> bool {
423423
!self.is_null(index)
424424
}
425+
426+
/// Returns an iterator over the values in this array
427+
pub fn iter(&self) -> VariantArrayIter<'_> {
428+
VariantArrayIter::new(self)
429+
}
425430
}
426431

427432
impl From<VariantArray> for StructArray {
@@ -436,6 +441,89 @@ impl From<VariantArray> for ArrayRef {
436441
}
437442
}
438443

444+
/// An iterator over [`VariantArray`]
445+
///
446+
/// This iterator returns `Option<Option<Variant<'a, 'a>>>` where:
447+
/// - `None` indicates the end of iteration
448+
/// - `Some(None)` indicates a null value at this position
449+
/// - `Some(Some(variant))` indicates a valid variant value
450+
///
451+
/// # Example
452+
///
453+
/// ```
454+
/// # use parquet_variant::Variant;
455+
/// # use parquet_variant_compute::VariantArrayBuilder;
456+
/// let mut builder = VariantArrayBuilder::new(10);
457+
/// builder.append_variant(Variant::from(42));
458+
/// builder.append_null();
459+
/// builder.append_variant(Variant::from("hello"));
460+
/// let array = builder.build();
461+
///
462+
/// let values = array.iter().collect::<Vec<_>>();
463+
/// assert_eq!(values.len(), 3);
464+
/// assert_eq!(values[0], Some(Variant::from(42)));
465+
/// assert_eq!(values[1], None);
466+
/// assert_eq!(values[2], Some(Variant::from("hello")));
467+
/// ```
468+
#[derive(Debug)]
469+
pub struct VariantArrayIter<'a> {
470+
array: &'a VariantArray,
471+
head_i: usize,
472+
tail_i: usize,
473+
}
474+
475+
impl<'a> VariantArrayIter<'a> {
476+
/// Creates a new iterator over the given [`VariantArray`]
477+
pub fn new(array: &'a VariantArray) -> Self {
478+
Self {
479+
array,
480+
head_i: 0,
481+
tail_i: array.len(),
482+
}
483+
}
484+
485+
fn value_opt(&self, i: usize) -> Option<Variant<'a, 'a>> {
486+
self.array.is_valid(i).then(|| self.array.value(i))
487+
}
488+
}
489+
490+
impl<'a> Iterator for VariantArrayIter<'a> {
491+
type Item = Option<Variant<'a, 'a>>;
492+
493+
#[inline]
494+
fn next(&mut self) -> Option<Self::Item> {
495+
if self.head_i == self.tail_i {
496+
return None;
497+
}
498+
499+
let out = self.value_opt(self.head_i);
500+
501+
self.head_i += 1;
502+
503+
Some(out)
504+
}
505+
506+
fn size_hint(&self) -> (usize, Option<usize>) {
507+
let remainder = self.tail_i - self.head_i;
508+
509+
(remainder, Some(remainder))
510+
}
511+
}
512+
513+
impl<'a> DoubleEndedIterator for VariantArrayIter<'a> {
514+
fn next_back(&mut self) -> Option<Self::Item> {
515+
if self.head_i == self.tail_i {
516+
return None;
517+
}
518+
519+
self.tail_i -= 1;
520+
521+
Some(self.value_opt(self.tail_i))
522+
}
523+
}
524+
525+
impl<'a> ExactSizeIterator for VariantArrayIter<'a> {}
526+
439527
/// One shredded field of a partially or prefectly shredded variant. For example, suppose the
440528
/// shredding schema for variant `v` treats it as an object with a single field `a`, where `a` is
441529
/// itself a struct with the single field `b` of type INT. Then the physical layout of the column
@@ -1062,6 +1150,8 @@ fn canonicalize_and_verify_field(field: &Arc<Field>) -> Result<Cow<'_, Arc<Field
10621150

10631151
#[cfg(test)]
10641152
mod test {
1153+
use crate::VariantArrayBuilder;
1154+
10651155
use super::*;
10661156
use arrow::array::{BinaryViewArray, Int32Array};
10671157
use arrow_schema::{Field, Fields};
@@ -1244,4 +1334,89 @@ mod test {
12441334
}
12451335
));
12461336
}
1337+
1338+
#[test]
1339+
fn test_variant_array_iterable() {
1340+
let mut b = VariantArrayBuilder::new(6);
1341+
1342+
b.append_null();
1343+
b.append_variant(Variant::from(1_i8));
1344+
b.append_variant(Variant::Null);
1345+
b.append_variant(Variant::from(2_i32));
1346+
b.append_variant(Variant::from(3_i64));
1347+
b.append_null();
1348+
1349+
let v = b.build();
1350+
1351+
let variants = v.iter().collect::<Vec<_>>();
1352+
1353+
assert_eq!(
1354+
variants,
1355+
vec![
1356+
None,
1357+
Some(Variant::Int8(1)),
1358+
Some(Variant::Null),
1359+
Some(Variant::Int32(2)),
1360+
Some(Variant::Int64(3)),
1361+
None,
1362+
]
1363+
);
1364+
}
1365+
1366+
#[test]
1367+
fn test_variant_array_iter_double_ended() {
1368+
let mut b = VariantArrayBuilder::new(5);
1369+
1370+
b.append_variant(Variant::from(0_i32));
1371+
b.append_null();
1372+
b.append_variant(Variant::from(2_i32));
1373+
b.append_null();
1374+
b.append_variant(Variant::from(4_i32));
1375+
1376+
let array = b.build();
1377+
let mut iter = array.iter();
1378+
1379+
assert_eq!(iter.next(), Some(Some(Variant::from(0_i32))));
1380+
assert_eq!(iter.next(), Some(None));
1381+
1382+
assert_eq!(iter.next_back(), Some(Some(Variant::from(4_i32))));
1383+
assert_eq!(iter.next_back(), Some(None));
1384+
assert_eq!(iter.next_back(), Some(Some(Variant::from(2_i32))));
1385+
1386+
assert_eq!(iter.next_back(), None);
1387+
assert_eq!(iter.next(), None);
1388+
}
1389+
1390+
#[test]
1391+
fn test_variant_array_iter_reverse() {
1392+
let mut b = VariantArrayBuilder::new(5);
1393+
1394+
b.append_variant(Variant::from("a"));
1395+
b.append_null();
1396+
b.append_variant(Variant::from("aaa"));
1397+
b.append_null();
1398+
b.append_variant(Variant::from("aaaaa"));
1399+
1400+
let array = b.build();
1401+
1402+
let result: Vec<_> = array.iter().rev().collect();
1403+
assert_eq!(
1404+
result,
1405+
vec![
1406+
Some(Variant::from("aaaaa")),
1407+
None,
1408+
Some(Variant::from("aaa")),
1409+
None,
1410+
Some(Variant::from("a")),
1411+
]
1412+
);
1413+
}
1414+
1415+
#[test]
1416+
fn test_variant_array_iter_empty() {
1417+
let v = VariantArrayBuilder::new(0).build();
1418+
let mut i = v.iter();
1419+
assert!(i.next().is_none());
1420+
assert!(i.next_back().is_none());
1421+
}
12471422
}

0 commit comments

Comments
 (0)