Path: blob/main/crates/polars-arrow/src/bitmap/utils/zip_validity.rs
6939 views
use crate::bitmap::Bitmap;1use crate::bitmap::utils::BitmapIter;2use crate::trusted_len::TrustedLen;34/// An [`Iterator`] over validity and values.5#[derive(Debug, Clone)]6pub struct ZipValidityIter<T, I, V>7where8I: Iterator<Item = T>,9V: Iterator<Item = bool>,10{11values: I,12validity: V,13}1415impl<T, I, V> ZipValidityIter<T, I, V>16where17I: Iterator<Item = T>,18V: Iterator<Item = bool>,19{20/// Creates a new [`ZipValidityIter`].21/// # Panics22/// This function panics if the size_hints of the iterators are different23pub fn new(values: I, validity: V) -> Self {24assert_eq!(values.size_hint(), validity.size_hint());25Self { values, validity }26}27}2829impl<T, I, V> Iterator for ZipValidityIter<T, I, V>30where31I: Iterator<Item = T>,32V: Iterator<Item = bool>,33{34type Item = Option<T>;3536#[inline]37fn next(&mut self) -> Option<Self::Item> {38let value = self.values.next();39let is_valid = self.validity.next();40is_valid41.zip(value)42.map(|(is_valid, value)| is_valid.then(|| value))43}4445#[inline]46fn size_hint(&self) -> (usize, Option<usize>) {47self.values.size_hint()48}4950#[inline]51fn nth(&mut self, n: usize) -> Option<Self::Item> {52let value = self.values.nth(n);53let is_valid = self.validity.nth(n);54is_valid55.zip(value)56.map(|(is_valid, value)| is_valid.then(|| value))57}58}5960impl<T, I, V> DoubleEndedIterator for ZipValidityIter<T, I, V>61where62I: DoubleEndedIterator<Item = T>,63V: DoubleEndedIterator<Item = bool>,64{65#[inline]66fn next_back(&mut self) -> Option<Self::Item> {67let value = self.values.next_back();68let is_valid = self.validity.next_back();69is_valid70.zip(value)71.map(|(is_valid, value)| is_valid.then(|| value))72}73}7475unsafe impl<T, I, V> TrustedLen for ZipValidityIter<T, I, V>76where77I: TrustedLen<Item = T>,78V: TrustedLen<Item = bool>,79{80}8182impl<T, I, V> ExactSizeIterator for ZipValidityIter<T, I, V>83where84I: ExactSizeIterator<Item = T>,85V: ExactSizeIterator<Item = bool>,86{87}8889/// An [`Iterator`] over [`Option<T>`]90/// This enum can be used in two distinct ways:91/// * as an iterator, via `Iterator::next`92/// * as an enum of two iterators, via `match self`93///94/// The latter allows specializalizing to when there are no nulls95#[derive(Debug, Clone)]96pub enum ZipValidity<T, I, V>97where98I: Iterator<Item = T>,99V: Iterator<Item = bool>,100{101/// There are no null values102Required(I),103/// There are null values104Optional(ZipValidityIter<T, I, V>),105}106107impl<T, I, V> ZipValidity<T, I, V>108where109I: Iterator<Item = T>,110V: Iterator<Item = bool>,111{112/// Returns a new [`ZipValidity`]113pub fn new(values: I, validity: Option<V>) -> Self {114match validity {115Some(validity) => Self::Optional(ZipValidityIter::new(values, validity)),116_ => Self::Required(values),117}118}119}120121impl<'a, T, I> ZipValidity<T, I, BitmapIter<'a>>122where123I: Iterator<Item = T>,124{125/// Returns a new [`ZipValidity`] and drops the `validity` if all values126/// are valid.127pub fn new_with_validity(values: I, validity: Option<&'a Bitmap>) -> Self {128// only if the validity has nulls we take the optional branch.129match validity.and_then(|validity| (validity.unset_bits() > 0).then(|| validity.iter())) {130Some(validity) => Self::Optional(ZipValidityIter::new(values, validity)),131_ => Self::Required(values),132}133}134}135136impl<T, I, V> Iterator for ZipValidity<T, I, V>137where138I: Iterator<Item = T>,139V: Iterator<Item = bool>,140{141type Item = Option<T>;142143#[inline]144fn next(&mut self) -> Option<Self::Item> {145match self {146Self::Required(values) => values.next().map(Some),147Self::Optional(zipped) => zipped.next(),148}149}150151#[inline]152fn size_hint(&self) -> (usize, Option<usize>) {153match self {154Self::Required(values) => values.size_hint(),155Self::Optional(zipped) => zipped.size_hint(),156}157}158159#[inline]160fn nth(&mut self, n: usize) -> Option<Self::Item> {161match self {162Self::Required(values) => values.nth(n).map(Some),163Self::Optional(zipped) => zipped.nth(n),164}165}166}167168impl<T, I, V> DoubleEndedIterator for ZipValidity<T, I, V>169where170I: DoubleEndedIterator<Item = T>,171V: DoubleEndedIterator<Item = bool>,172{173#[inline]174fn next_back(&mut self) -> Option<Self::Item> {175match self {176Self::Required(values) => values.next_back().map(Some),177Self::Optional(zipped) => zipped.next_back(),178}179}180}181182impl<T, I, V> ExactSizeIterator for ZipValidity<T, I, V>183where184I: ExactSizeIterator<Item = T>,185V: ExactSizeIterator<Item = bool>,186{187}188189unsafe impl<T, I, V> TrustedLen for ZipValidity<T, I, V>190where191I: TrustedLen<Item = T>,192V: TrustedLen<Item = bool>,193{194}195196impl<T, I, V> ZipValidity<T, I, V>197where198I: Iterator<Item = T>,199V: Iterator<Item = bool>,200{201/// Unwrap into an iterator that has no null values.202pub fn unwrap_required(self) -> I {203match self {204ZipValidity::Required(i) => i,205_ => panic!("Could not 'unwrap_required'. 'ZipValidity' iterator has nulls."),206}207}208209/// Unwrap into an iterator that has null values.210pub fn unwrap_optional(self) -> ZipValidityIter<T, I, V> {211match self {212ZipValidity::Optional(i) => i,213_ => panic!("Could not 'unwrap_optional'. 'ZipValidity' iterator has no nulls."),214}215}216}217218219