Skip to main content

arrow_array/array/
boolean_array.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::array::print_long_array;
19use crate::builder::BooleanBuilder;
20use crate::iterator::BooleanIter;
21use crate::{Array, ArrayAccessor, ArrayRef, Scalar};
22use arrow_buffer::bit_chunk_iterator::UnalignedBitChunk;
23use arrow_buffer::{BooleanBuffer, Buffer, MutableBuffer, NullBuffer, bit_util};
24use arrow_data::{ArrayData, ArrayDataBuilder};
25use arrow_schema::DataType;
26use std::any::Any;
27use std::sync::Arc;
28
29/// An array of [boolean values](https://arrow.apache.org/docs/format/Columnar.html#fixed-size-primitive-layout)
30///
31/// # Example: From a Vec
32///
33/// ```
34/// # use arrow_array::{Array, BooleanArray};
35/// let arr: BooleanArray = vec![true, true, false].into();
36/// ```
37///
38/// # Example: From an optional Vec
39///
40/// ```
41/// # use arrow_array::{Array, BooleanArray};
42/// let arr: BooleanArray = vec![Some(true), None, Some(false)].into();
43/// ```
44///
45/// # Example: From an iterator
46///
47/// ```
48/// # use arrow_array::{Array, BooleanArray};
49/// let arr: BooleanArray = (0..5).map(|x| (x % 2 == 0).then(|| x % 3 == 0)).collect();
50/// let values: Vec<_> = arr.iter().collect();
51/// assert_eq!(&values, &[Some(true), None, Some(false), None, Some(false)])
52/// ```
53///
54/// # Example: Using Builder
55///
56/// ```
57/// # use arrow_array::Array;
58/// # use arrow_array::builder::BooleanBuilder;
59/// let mut builder = BooleanBuilder::new();
60/// builder.append_value(true);
61/// builder.append_null();
62/// builder.append_value(false);
63/// let array = builder.finish();
64/// let values: Vec<_> = array.iter().collect();
65/// assert_eq!(&values, &[Some(true), None, Some(false)])
66/// ```
67///
68#[derive(Clone)]
69pub struct BooleanArray {
70    values: BooleanBuffer,
71    nulls: Option<NullBuffer>,
72}
73
74impl std::fmt::Debug for BooleanArray {
75    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
76        write!(f, "BooleanArray\n[\n")?;
77        print_long_array(self, f, |array, index, f| {
78            std::fmt::Debug::fmt(&array.value(index), f)
79        })?;
80        write!(f, "]")
81    }
82}
83
84impl BooleanArray {
85    /// Create a new [`BooleanArray`] from the provided values and nulls
86    ///
87    /// # Panics
88    ///
89    /// Panics if `values.len() != nulls.len()`
90    pub fn new(values: BooleanBuffer, nulls: Option<NullBuffer>) -> Self {
91        if let Some(n) = nulls.as_ref() {
92            assert_eq!(values.len(), n.len());
93        }
94        Self { values, nulls }
95    }
96
97    /// Create a new [`BooleanArray`] with length `len` consisting only of nulls
98    pub fn new_null(len: usize) -> Self {
99        Self {
100            values: BooleanBuffer::new_unset(len),
101            nulls: Some(NullBuffer::new_null(len)),
102        }
103    }
104
105    /// Create a new [`Scalar`] from `value`
106    pub fn new_scalar(value: bool) -> Scalar<Self> {
107        let values = match value {
108            true => BooleanBuffer::new_set(1),
109            false => BooleanBuffer::new_unset(1),
110        };
111        Scalar::new(Self::new(values, None))
112    }
113
114    /// Create a new [`BooleanArray`] from a [`Buffer`] specified by `offset` and `len`, the `offset` and `len` in bits
115    /// Logically convert each bit in [`Buffer`] to boolean and use it to build [`BooleanArray`].
116    /// using this method will make the following points self-evident:
117    /// * there is no `null` in the constructed [`BooleanArray`];
118    /// * without considering `buffer.into()`, this method is efficient because there is no need to perform pack and unpack operations on boolean;
119    pub fn new_from_packed(buffer: impl Into<Buffer>, offset: usize, len: usize) -> Self {
120        BooleanBuffer::new(buffer.into(), offset, len).into()
121    }
122
123    /// Create a new [`BooleanArray`] from `&[u8]`
124    /// This method uses `new_from_packed` and constructs a [`Buffer`] using `value`, and offset is set to 0 and len is set to `value.len() * 8`
125    /// using this method will make the following points self-evident:
126    /// * there is no `null` in the constructed [`BooleanArray`];
127    /// * the length of the constructed [`BooleanArray`] is always a multiple of 8;
128    pub fn new_from_u8(value: &[u8]) -> Self {
129        BooleanBuffer::new(Buffer::from(value), 0, value.len() * 8).into()
130    }
131
132    /// Returns the length of this array.
133    pub fn len(&self) -> usize {
134        self.values.len()
135    }
136
137    /// Returns whether this array is empty.
138    pub fn is_empty(&self) -> bool {
139        self.values.is_empty()
140    }
141
142    /// Returns a zero-copy slice of this array with the indicated offset and length.
143    pub fn slice(&self, offset: usize, length: usize) -> Self {
144        Self {
145            values: self.values.slice(offset, length),
146            nulls: self.nulls.as_ref().map(|n| n.slice(offset, length)),
147        }
148    }
149
150    /// Returns a new boolean array builder
151    pub fn builder(capacity: usize) -> BooleanBuilder {
152        BooleanBuilder::with_capacity(capacity)
153    }
154
155    /// Returns the underlying [`BooleanBuffer`] holding all the values of this array
156    pub fn values(&self) -> &BooleanBuffer {
157        &self.values
158    }
159
160    /// Block size for chunked fold operations in [`Self::has_true`] and [`Self::has_false`].
161    /// Using `chunks_exact` with this size lets the compiler fully unroll the inner
162    /// fold (no inner branch/loop), enabling short-circuit exits every N chunks.
163    const CHUNK_FOLD_BLOCK_SIZE: usize = 16;
164
165    /// Returns an [`UnalignedBitChunk`] over this array's values.
166    fn unaligned_bit_chunks(&self) -> UnalignedBitChunk<'_> {
167        UnalignedBitChunk::new(self.values().values(), self.values().offset(), self.len())
168    }
169
170    /// Returns the number of non null, true values within this array.
171    /// If you only need to check if there is at least one true value, consider using `has_true()` which can short-circuit and be more efficient.
172    pub fn true_count(&self) -> usize {
173        match self.nulls() {
174            Some(nulls) => {
175                let null_chunks = nulls.inner().bit_chunks().iter_padded();
176                let value_chunks = self.values().bit_chunks().iter_padded();
177                null_chunks
178                    .zip(value_chunks)
179                    .map(|(a, b)| (a & b).count_ones() as usize)
180                    .sum()
181            }
182            None => self.values().count_set_bits(),
183        }
184    }
185
186    /// Returns the number of non null, false values within this array.
187    /// If you only need to check if there is at least one false value, consider using `has_false()` which can short-circuit and be more efficient.
188    pub fn false_count(&self) -> usize {
189        self.len() - self.null_count() - self.true_count()
190    }
191
192    /// Returns whether there is at least one non-null `true` value in this array.
193    ///
194    /// This is more efficient than `true_count() > 0` because it can short-circuit
195    /// as soon as a `true` value is found, without counting all set bits.
196    ///
197    /// Null values are not counted as `true`. Returns `false` for empty arrays.
198    pub fn has_true(&self) -> bool {
199        match self.nulls() {
200            Some(nulls) => {
201                let null_chunks = nulls.inner().bit_chunks().iter_padded();
202                let value_chunks = self.values().bit_chunks().iter_padded();
203                null_chunks.zip(value_chunks).any(|(n, v)| (n & v) != 0)
204            }
205            None => {
206                let bit_chunks = self.unaligned_bit_chunks();
207                let chunks = bit_chunks.chunks();
208                let mut exact = chunks.chunks_exact(Self::CHUNK_FOLD_BLOCK_SIZE);
209                let found = bit_chunks.prefix().unwrap_or(0) != 0
210                    || exact.any(|block| block.iter().fold(0u64, |acc, &c| acc | c) != 0);
211                found
212                    || exact.remainder().iter().any(|&c| c != 0)
213                    || bit_chunks.suffix().unwrap_or(0) != 0
214            }
215        }
216    }
217
218    /// Returns whether there is at least one non-null `false` value in this array.
219    ///
220    /// This is more efficient than `false_count() > 0` because it can short-circuit
221    /// as soon as a `false` value is found, without counting all set bits.
222    ///
223    /// Null values are not counted as `false`. Returns `false` for empty arrays.
224    pub fn has_false(&self) -> bool {
225        match self.nulls() {
226            Some(nulls) => {
227                let null_chunks = nulls.inner().bit_chunks().iter_padded();
228                let value_chunks = self.values().bit_chunks().iter_padded();
229                null_chunks.zip(value_chunks).any(|(n, v)| (n & !v) != 0)
230            }
231            None => {
232                let bit_chunks = self.unaligned_bit_chunks();
233                // UnalignedBitChunk zeros padding bits; fill them with 1s so
234                // they don't appear as false values.
235                let lead_mask = !((1u64 << bit_chunks.lead_padding()) - 1);
236                let trail_mask = if bit_chunks.trailing_padding() == 0 {
237                    u64::MAX
238                } else {
239                    (1u64 << (64 - bit_chunks.trailing_padding())) - 1
240                };
241                let (prefix_fill, suffix_fill) = match (bit_chunks.prefix(), bit_chunks.suffix()) {
242                    (Some(_), Some(_)) => (!lead_mask, !trail_mask),
243                    (Some(_), None) => (!lead_mask | !trail_mask, 0),
244                    (None, Some(_)) => (0, !trail_mask),
245                    (None, None) => (0, 0),
246                };
247                let chunks = bit_chunks.chunks();
248                let mut exact = chunks.chunks_exact(Self::CHUNK_FOLD_BLOCK_SIZE);
249                let found = bit_chunks
250                    .prefix()
251                    .is_some_and(|v| (v | prefix_fill) != u64::MAX)
252                    || exact
253                        .any(|block| block.iter().fold(u64::MAX, |acc, &c| acc & c) != u64::MAX);
254                found
255                    || exact.remainder().iter().any(|&c| c != u64::MAX)
256                    || bit_chunks
257                        .suffix()
258                        .is_some_and(|v| (v | suffix_fill) != u64::MAX)
259            }
260        }
261    }
262
263    /// Returns the boolean value at index `i`.
264    ///
265    /// Note: This method does not check for nulls and the value is arbitrary
266    /// if [`is_null`](Self::is_null) returns true for the index.
267    ///
268    /// # Safety
269    /// This doesn't check bounds, the caller must ensure that index < self.len()
270    pub unsafe fn value_unchecked(&self, i: usize) -> bool {
271        unsafe { self.values.value_unchecked(i) }
272    }
273
274    /// Returns the boolean value at index `i`.
275    ///
276    /// Note: This method does not check for nulls and the value is arbitrary
277    /// if [`is_null`](Self::is_null) returns true for the index.
278    ///
279    /// # Panics
280    /// Panics if index `i` is out of bounds
281    pub fn value(&self, i: usize) -> bool {
282        assert!(
283            i < self.len(),
284            "Trying to access an element at index {} from a BooleanArray of length {}",
285            i,
286            self.len()
287        );
288        // Safety:
289        // `i < self.len()
290        unsafe { self.value_unchecked(i) }
291    }
292
293    /// Returns an iterator that returns the values of `array.value(i)` for an iterator with each element `i`
294    pub fn take_iter<'a>(
295        &'a self,
296        indexes: impl Iterator<Item = Option<usize>> + 'a,
297    ) -> impl Iterator<Item = Option<bool>> + 'a {
298        indexes.map(|opt_index| opt_index.map(|index| self.value(index)))
299    }
300
301    /// Returns an iterator that returns the values of `array.value(i)` for an iterator with each element `i`
302    /// # Safety
303    ///
304    /// caller must ensure that the offsets in the iterator are less than the array len()
305    pub unsafe fn take_iter_unchecked<'a>(
306        &'a self,
307        indexes: impl Iterator<Item = Option<usize>> + 'a,
308    ) -> impl Iterator<Item = Option<bool>> + 'a {
309        indexes.map(|opt_index| opt_index.map(|index| unsafe { self.value_unchecked(index) }))
310    }
311
312    /// Create a [`BooleanArray`] by evaluating the operation for
313    /// each element of the provided array
314    ///
315    /// ```
316    /// # use arrow_array::{BooleanArray, Int32Array};
317    ///
318    /// let array = Int32Array::from(vec![1, 2, 3, 4, 5]);
319    /// let r = BooleanArray::from_unary(&array, |x| x > 2);
320    /// assert_eq!(&r, &BooleanArray::from(vec![false, false, true, true, true]));
321    /// ```
322    pub fn from_unary<T: ArrayAccessor, F>(left: T, mut op: F) -> Self
323    where
324        F: FnMut(T::Item) -> bool,
325    {
326        let nulls = left.logical_nulls();
327        let values = BooleanBuffer::collect_bool(left.len(), |i| unsafe {
328            // SAFETY: i in range 0..len
329            op(left.value_unchecked(i))
330        });
331        Self::new(values, nulls)
332    }
333
334    /// Create a [`BooleanArray`] by evaluating the binary operation for
335    /// each element of the provided arrays
336    ///
337    /// ```
338    /// # use arrow_array::{BooleanArray, Int32Array};
339    ///
340    /// let a = Int32Array::from(vec![1, 2, 3, 4, 5]);
341    /// let b = Int32Array::from(vec![1, 2, 0, 2, 5]);
342    /// let r = BooleanArray::from_binary(&a, &b, |a, b| a == b);
343    /// assert_eq!(&r, &BooleanArray::from(vec![true, true, false, false, true]));
344    /// ```
345    ///
346    /// # Panics
347    ///
348    /// This function panics if left and right are not the same length
349    ///
350    pub fn from_binary<T: ArrayAccessor, S: ArrayAccessor, F>(left: T, right: S, mut op: F) -> Self
351    where
352        F: FnMut(T::Item, S::Item) -> bool,
353    {
354        assert_eq!(left.len(), right.len());
355
356        let nulls = NullBuffer::union(
357            left.logical_nulls().as_ref(),
358            right.logical_nulls().as_ref(),
359        );
360        let values = BooleanBuffer::collect_bool(left.len(), |i| unsafe {
361            // SAFETY: i in range 0..len
362            op(left.value_unchecked(i), right.value_unchecked(i))
363        });
364        Self::new(values, nulls)
365    }
366
367    /// Deconstruct this array into its constituent parts
368    pub fn into_parts(self) -> (BooleanBuffer, Option<NullBuffer>) {
369        (self.values, self.nulls)
370    }
371}
372
373/// SAFETY: Correctly implements the contract of Arrow Arrays
374unsafe impl Array for BooleanArray {
375    fn as_any(&self) -> &dyn Any {
376        self
377    }
378
379    fn to_data(&self) -> ArrayData {
380        self.clone().into()
381    }
382
383    fn into_data(self) -> ArrayData {
384        self.into()
385    }
386
387    fn data_type(&self) -> &DataType {
388        &DataType::Boolean
389    }
390
391    fn slice(&self, offset: usize, length: usize) -> ArrayRef {
392        Arc::new(self.slice(offset, length))
393    }
394
395    fn len(&self) -> usize {
396        self.values.len()
397    }
398
399    fn is_empty(&self) -> bool {
400        self.values.is_empty()
401    }
402
403    fn shrink_to_fit(&mut self) {
404        self.values.shrink_to_fit();
405        if let Some(nulls) = &mut self.nulls {
406            nulls.shrink_to_fit();
407        }
408    }
409
410    fn offset(&self) -> usize {
411        self.values.offset()
412    }
413
414    fn nulls(&self) -> Option<&NullBuffer> {
415        self.nulls.as_ref()
416    }
417
418    fn logical_null_count(&self) -> usize {
419        self.null_count()
420    }
421
422    fn get_buffer_memory_size(&self) -> usize {
423        let mut sum = self.values.inner().capacity();
424        if let Some(x) = &self.nulls {
425            sum += x.buffer().capacity()
426        }
427        sum
428    }
429
430    fn get_array_memory_size(&self) -> usize {
431        std::mem::size_of::<Self>() + self.get_buffer_memory_size()
432    }
433
434    #[cfg(feature = "pool")]
435    fn claim(&self, pool: &dyn arrow_buffer::MemoryPool) {
436        self.values.claim(pool);
437        if let Some(nulls) = &self.nulls {
438            nulls.claim(pool);
439        }
440    }
441}
442
443impl ArrayAccessor for &BooleanArray {
444    type Item = bool;
445
446    fn value(&self, index: usize) -> Self::Item {
447        BooleanArray::value(self, index)
448    }
449
450    unsafe fn value_unchecked(&self, index: usize) -> Self::Item {
451        unsafe { BooleanArray::value_unchecked(self, index) }
452    }
453}
454
455impl From<Vec<bool>> for BooleanArray {
456    fn from(data: Vec<bool>) -> Self {
457        let mut mut_buf = MutableBuffer::new_null(data.len());
458        {
459            let mut_slice = mut_buf.as_slice_mut();
460            for (i, b) in data.iter().enumerate() {
461                if *b {
462                    bit_util::set_bit(mut_slice, i);
463                }
464            }
465        }
466        let array_data = ArrayData::builder(DataType::Boolean)
467            .len(data.len())
468            .add_buffer(mut_buf.into());
469
470        let array_data = unsafe { array_data.build_unchecked() };
471        BooleanArray::from(array_data)
472    }
473}
474
475impl From<Vec<Option<bool>>> for BooleanArray {
476    fn from(data: Vec<Option<bool>>) -> Self {
477        data.iter().collect()
478    }
479}
480
481impl From<ArrayData> for BooleanArray {
482    fn from(data: ArrayData) -> Self {
483        let (data_type, len, nulls, offset, mut buffers, _child_data) = data.into_parts();
484        assert_eq!(
485            data_type,
486            DataType::Boolean,
487            "BooleanArray expected ArrayData with type Boolean got {data_type:?}",
488        );
489        assert_eq!(
490            buffers.len(),
491            1,
492            "BooleanArray data should contain a single buffer only (values buffer)"
493        );
494        let buffer = buffers.pop().expect("checked above");
495        let values = BooleanBuffer::new(buffer, offset, len);
496
497        Self { values, nulls }
498    }
499}
500
501impl From<BooleanArray> for ArrayData {
502    fn from(array: BooleanArray) -> Self {
503        let builder = ArrayDataBuilder::new(DataType::Boolean)
504            .len(array.values.len())
505            .offset(array.values.offset())
506            .nulls(array.nulls)
507            .buffers(vec![array.values.into_inner()]);
508
509        unsafe { builder.build_unchecked() }
510    }
511}
512
513impl<'a> IntoIterator for &'a BooleanArray {
514    type Item = Option<bool>;
515    type IntoIter = BooleanIter<'a>;
516
517    fn into_iter(self) -> Self::IntoIter {
518        BooleanIter::<'a>::new(self)
519    }
520}
521
522impl<'a> BooleanArray {
523    /// constructs a new iterator
524    pub fn iter(&'a self) -> BooleanIter<'a> {
525        BooleanIter::<'a>::new(self)
526    }
527}
528
529/// An optional boolean value
530///
531/// This struct is used as an adapter when creating `BooleanArray` from an iterator.
532/// `FromIterator` for `BooleanArray` takes an iterator where the elements can be `into`
533/// this struct. So once implementing `From` or `Into` trait for a type, an iterator of
534/// the type can be collected to `BooleanArray`.
535///
536/// See also [NativeAdapter](crate::array::NativeAdapter).
537#[derive(Debug)]
538struct BooleanAdapter {
539    /// Corresponding Rust native type if available
540    pub native: Option<bool>,
541}
542
543impl From<bool> for BooleanAdapter {
544    fn from(value: bool) -> Self {
545        BooleanAdapter {
546            native: Some(value),
547        }
548    }
549}
550
551impl From<&bool> for BooleanAdapter {
552    fn from(value: &bool) -> Self {
553        BooleanAdapter {
554            native: Some(*value),
555        }
556    }
557}
558
559impl From<Option<bool>> for BooleanAdapter {
560    fn from(value: Option<bool>) -> Self {
561        BooleanAdapter { native: value }
562    }
563}
564
565impl From<&Option<bool>> for BooleanAdapter {
566    fn from(value: &Option<bool>) -> Self {
567        BooleanAdapter { native: *value }
568    }
569}
570
571impl<Ptr: Into<BooleanAdapter>> FromIterator<Ptr> for BooleanArray {
572    fn from_iter<I: IntoIterator<Item = Ptr>>(iter: I) -> Self {
573        let iter = iter.into_iter();
574        let capacity = match iter.size_hint() {
575            (lower, Some(upper)) if lower == upper => lower,
576            _ => 0,
577        };
578        let mut builder = BooleanBuilder::with_capacity(capacity);
579        builder.extend(iter.map(|item| item.into().native));
580        builder.finish()
581    }
582}
583
584impl BooleanArray {
585    /// Creates a [`BooleanArray`] from an iterator of trusted length.
586    ///
587    /// # Safety
588    ///
589    /// The iterator must be [`TrustedLen`](https://doc.rust-lang.org/std/iter/trait.TrustedLen.html).
590    /// I.e. that `size_hint().1` correctly reports its length. Note that this is a stronger
591    /// guarantee that `ExactSizeIterator` provides which could still report a wrong length.
592    ///
593    /// # Panics
594    ///
595    /// Panics if the iterator does not report an upper bound on `size_hint()`.
596    #[inline]
597    #[allow(
598        private_bounds,
599        reason = "We will expose BooleanAdapter if there is a need"
600    )]
601    pub unsafe fn from_trusted_len_iter<I, P>(iter: I) -> Self
602    where
603        P: Into<BooleanAdapter>,
604        I: ExactSizeIterator<Item = P>,
605    {
606        let data_len = iter.len();
607
608        let num_bytes = bit_util::ceil(data_len, 8);
609        let mut null_builder = MutableBuffer::from_len_zeroed(num_bytes);
610        let mut val_builder = MutableBuffer::from_len_zeroed(num_bytes);
611
612        let data = val_builder.as_slice_mut();
613
614        let null_slice = null_builder.as_slice_mut();
615        iter.enumerate().for_each(|(i, item)| {
616            if let Some(a) = item.into().native {
617                unsafe {
618                    // SAFETY: There will be enough space in the buffers due to the trusted len size
619                    // hint
620                    bit_util::set_bit_raw(null_slice.as_mut_ptr(), i);
621                    if a {
622                        bit_util::set_bit_raw(data.as_mut_ptr(), i);
623                    }
624                }
625            }
626        });
627
628        let values = BooleanBuffer::new(val_builder.into(), 0, data_len);
629        let nulls = NullBuffer::from_unsliced_buffer(null_builder, data_len);
630        BooleanArray::new(values, nulls)
631    }
632}
633
634impl From<BooleanBuffer> for BooleanArray {
635    fn from(values: BooleanBuffer) -> Self {
636        Self {
637            values,
638            nulls: None,
639        }
640    }
641}
642
643#[cfg(test)]
644mod tests {
645    use super::*;
646    use arrow_buffer::Buffer;
647    use rand::{Rng, rng};
648
649    #[test]
650    fn test_boolean_fmt_debug() {
651        let arr = BooleanArray::from(vec![true, false, false]);
652        assert_eq!(
653            "BooleanArray\n[\n  true,\n  false,\n  false,\n]",
654            format!("{arr:?}")
655        );
656    }
657
658    #[test]
659    fn test_boolean_with_null_fmt_debug() {
660        let mut builder = BooleanArray::builder(3);
661        builder.append_value(true);
662        builder.append_null();
663        builder.append_value(false);
664        let arr = builder.finish();
665        assert_eq!(
666            "BooleanArray\n[\n  true,\n  null,\n  false,\n]",
667            format!("{arr:?}")
668        );
669    }
670
671    #[test]
672    fn test_boolean_array_from_vec() {
673        let buf = Buffer::from([10_u8]);
674        let arr = BooleanArray::from(vec![false, true, false, true]);
675        assert_eq!(&buf, arr.values().inner());
676        assert_eq!(4, arr.len());
677        assert_eq!(0, arr.offset());
678        assert_eq!(0, arr.null_count());
679        for i in 0..4 {
680            assert!(!arr.is_null(i));
681            assert!(arr.is_valid(i));
682            assert_eq!(i == 1 || i == 3, arr.value(i), "failed at {i}")
683        }
684    }
685
686    #[test]
687    fn test_boolean_array_from_vec_option() {
688        let buf = Buffer::from([10_u8]);
689        let arr = BooleanArray::from(vec![Some(false), Some(true), None, Some(true)]);
690        assert_eq!(&buf, arr.values().inner());
691        assert_eq!(4, arr.len());
692        assert_eq!(0, arr.offset());
693        assert_eq!(1, arr.null_count());
694        for i in 0..4 {
695            if i == 2 {
696                assert!(arr.is_null(i));
697                assert!(!arr.is_valid(i));
698            } else {
699                assert!(!arr.is_null(i));
700                assert!(arr.is_valid(i));
701                assert_eq!(i == 1 || i == 3, arr.value(i), "failed at {i}")
702            }
703        }
704    }
705
706    #[test]
707    fn test_boolean_array_from_packed() {
708        let v = [1_u8, 2_u8, 3_u8];
709        let arr = BooleanArray::new_from_packed(v, 0, 24);
710        assert_eq!(24, arr.len());
711        assert_eq!(0, arr.offset());
712        assert_eq!(0, arr.null_count());
713        assert!(arr.nulls.is_none());
714        for i in 0..24 {
715            assert!(!arr.is_null(i));
716            assert!(arr.is_valid(i));
717            assert_eq!(
718                i == 0 || i == 9 || i == 16 || i == 17,
719                arr.value(i),
720                "failed t {i}"
721            )
722        }
723    }
724
725    #[test]
726    fn test_boolean_array_from_slice_u8() {
727        let v: Vec<u8> = vec![1, 2, 3];
728        let slice = &v[..];
729        let arr = BooleanArray::new_from_u8(slice);
730        assert_eq!(24, arr.len());
731        assert_eq!(0, arr.offset());
732        assert_eq!(0, arr.null_count());
733        assert!(arr.nulls().is_none());
734        for i in 0..24 {
735            assert!(!arr.is_null(i));
736            assert!(arr.is_valid(i));
737            assert_eq!(
738                i == 0 || i == 9 || i == 16 || i == 17,
739                arr.value(i),
740                "failed t {i}"
741            )
742        }
743    }
744
745    #[test]
746    fn test_boolean_array_from_iter() {
747        let v = vec![Some(false), Some(true), Some(false), Some(true)];
748        let arr = v.into_iter().collect::<BooleanArray>();
749        assert_eq!(4, arr.len());
750        assert_eq!(0, arr.offset());
751        assert_eq!(0, arr.null_count());
752        assert!(arr.nulls().is_none());
753        for i in 0..3 {
754            assert!(!arr.is_null(i));
755            assert!(arr.is_valid(i));
756            assert_eq!(i == 1 || i == 3, arr.value(i), "failed at {i}")
757        }
758    }
759
760    #[test]
761    fn test_boolean_array_from_non_nullable_iter() {
762        let v = vec![true, false, true];
763        let arr = v.into_iter().collect::<BooleanArray>();
764        assert_eq!(3, arr.len());
765        assert_eq!(0, arr.offset());
766        assert_eq!(0, arr.null_count());
767        assert!(arr.nulls().is_none());
768
769        assert!(arr.value(0));
770        assert!(!arr.value(1));
771        assert!(arr.value(2));
772    }
773
774    #[test]
775    fn test_boolean_array_from_nullable_iter() {
776        let v = vec![Some(true), None, Some(false), None];
777        let arr = v.into_iter().collect::<BooleanArray>();
778        assert_eq!(4, arr.len());
779        assert_eq!(0, arr.offset());
780        assert_eq!(2, arr.null_count());
781        assert!(arr.nulls().is_some());
782
783        assert!(arr.is_valid(0));
784        assert!(arr.is_null(1));
785        assert!(arr.is_valid(2));
786        assert!(arr.is_null(3));
787
788        assert!(arr.value(0));
789        assert!(!arr.value(2));
790    }
791
792    #[test]
793    fn test_boolean_array_from_nullable_trusted_len_iter() {
794        // Should exhibit the same behavior as `from_iter`, which is tested above.
795        let v = vec![Some(true), None, Some(false), None];
796        let expected = v.clone().into_iter().collect::<BooleanArray>();
797        let actual = unsafe {
798            // SAFETY: `v` has trusted length
799            BooleanArray::from_trusted_len_iter(v.into_iter())
800        };
801        assert_eq!(expected, actual);
802    }
803
804    #[test]
805    fn test_boolean_array_from_iter_with_larger_upper_bound() {
806        // See https://github.com/apache/arrow-rs/issues/8505
807        // This returns an upper size hint of 4
808        let iterator = vec![Some(true), None, Some(false), None]
809            .into_iter()
810            .filter(Option::is_some);
811        let arr = iterator.collect::<BooleanArray>();
812        assert_eq!(2, arr.len());
813    }
814
815    #[test]
816    fn test_boolean_array_builder() {
817        // Test building a boolean array with ArrayData builder and offset
818        // 000011011
819        let buf = Buffer::from([27_u8]);
820        let buf2 = buf.clone();
821        let data = ArrayData::builder(DataType::Boolean)
822            .len(5)
823            .offset(2)
824            .add_buffer(buf)
825            .build()
826            .unwrap();
827        let arr = BooleanArray::from(data);
828        assert_eq!(&buf2, arr.values().inner());
829        assert_eq!(5, arr.len());
830        assert_eq!(2, arr.offset());
831        assert_eq!(0, arr.null_count());
832        for i in 0..3 {
833            assert_eq!(i != 0, arr.value(i), "failed at {i}");
834        }
835    }
836
837    #[test]
838    #[should_panic(
839        expected = "Trying to access an element at index 4 from a BooleanArray of length 3"
840    )]
841    fn test_fixed_size_binary_array_get_value_index_out_of_bound() {
842        let v = vec![Some(true), None, Some(false)];
843        let array = v.into_iter().collect::<BooleanArray>();
844
845        array.value(4);
846    }
847
848    #[test]
849    #[should_panic(expected = "BooleanArray data should contain a single buffer only \
850                               (values buffer)")]
851    // Different error messages, so skip for now
852    // https://github.com/apache/arrow-rs/issues/1545
853    #[cfg(not(feature = "force_validate"))]
854    fn test_boolean_array_invalid_buffer_len() {
855        let data = unsafe {
856            ArrayData::builder(DataType::Boolean)
857                .len(5)
858                .build_unchecked()
859        };
860        drop(BooleanArray::from(data));
861    }
862
863    #[test]
864    #[should_panic(expected = "BooleanArray expected ArrayData with type Boolean got Int32")]
865    fn test_from_array_data_validation() {
866        let _ = BooleanArray::from(ArrayData::new_empty(&DataType::Int32));
867    }
868
869    #[test]
870    #[cfg_attr(miri, ignore)] // Takes too long
871    fn test_true_false_count() {
872        let mut rng = rng();
873
874        for _ in 0..10 {
875            // No nulls
876            let d: Vec<_> = (0..2000).map(|_| rng.random_bool(0.5)).collect();
877            let b = BooleanArray::from(d.clone());
878
879            let expected_true = d.iter().filter(|x| **x).count();
880            assert_eq!(b.true_count(), expected_true);
881            assert_eq!(b.false_count(), d.len() - expected_true);
882
883            // With nulls
884            let d: Vec<_> = (0..2000)
885                .map(|_| rng.random_bool(0.5).then(|| rng.random_bool(0.5)))
886                .collect();
887            let b = BooleanArray::from(d.clone());
888
889            let expected_true = d.iter().filter(|x| matches!(x, Some(true))).count();
890            assert_eq!(b.true_count(), expected_true);
891
892            let expected_false = d.iter().filter(|x| matches!(x, Some(false))).count();
893            assert_eq!(b.false_count(), expected_false);
894        }
895    }
896
897    #[test]
898    fn test_into_parts() {
899        let boolean_array = [Some(true), None, Some(false)]
900            .into_iter()
901            .collect::<BooleanArray>();
902        let (values, nulls) = boolean_array.into_parts();
903        assert_eq!(values.values(), &[0b0000_0001]);
904        assert!(nulls.is_some());
905        assert_eq!(nulls.unwrap().buffer().as_slice(), &[0b0000_0101]);
906
907        let boolean_array =
908            BooleanArray::from(vec![false, false, false, false, false, false, false, true]);
909        let (values, nulls) = boolean_array.into_parts();
910        assert_eq!(values.values(), &[0b1000_0000]);
911        assert!(nulls.is_none());
912    }
913
914    #[test]
915    fn test_new_null_array() {
916        let arr = BooleanArray::new_null(5);
917
918        assert_eq!(arr.len(), 5);
919        assert_eq!(arr.null_count(), 5);
920        assert_eq!(arr.true_count(), 0);
921        assert_eq!(arr.false_count(), 0);
922
923        for i in 0..5 {
924            assert!(arr.is_null(i));
925            assert!(!arr.is_valid(i));
926        }
927    }
928
929    #[test]
930    fn test_slice_with_nulls() {
931        let arr = BooleanArray::from(vec![Some(true), None, Some(false)]);
932        let sliced = arr.slice(1, 2);
933
934        assert_eq!(sliced.len(), 2);
935        assert_eq!(sliced.null_count(), 1);
936
937        assert!(sliced.is_null(0));
938        assert!(sliced.is_valid(1));
939        assert!(!sliced.value(1));
940    }
941
942    #[test]
943    fn test_has_true_has_false_all_true() {
944        let arr = BooleanArray::from(vec![true, true, true]);
945        assert!(arr.has_true());
946        assert!(!arr.has_false());
947    }
948
949    #[test]
950    fn test_has_true_has_false_all_false() {
951        let arr = BooleanArray::from(vec![false, false, false]);
952        assert!(!arr.has_true());
953        assert!(arr.has_false());
954    }
955
956    #[test]
957    fn test_has_true_has_false_mixed() {
958        let arr = BooleanArray::from(vec![true, false, true]);
959        assert!(arr.has_true());
960        assert!(arr.has_false());
961    }
962
963    #[test]
964    fn test_has_true_has_false_empty() {
965        let arr = BooleanArray::from(Vec::<bool>::new());
966        assert!(!arr.has_true());
967        assert!(!arr.has_false());
968    }
969
970    #[test]
971    fn test_has_true_has_false_nulls_all_valid_true() {
972        let arr = BooleanArray::from(vec![Some(true), None, Some(true)]);
973        assert!(arr.has_true());
974        assert!(!arr.has_false());
975    }
976
977    #[test]
978    fn test_has_true_has_false_nulls_all_valid_false() {
979        let arr = BooleanArray::from(vec![Some(false), None, Some(false)]);
980        assert!(!arr.has_true());
981        assert!(arr.has_false());
982    }
983
984    #[test]
985    fn test_has_true_has_false_all_null() {
986        let arr = BooleanArray::new_null(5);
987        assert!(!arr.has_true());
988        assert!(!arr.has_false());
989    }
990
991    #[test]
992    fn test_has_false_aligned_suffix_all_true() {
993        let arr = BooleanArray::from(vec![true; 129]);
994        assert!(arr.has_true());
995        assert!(!arr.has_false());
996    }
997
998    #[test]
999    fn test_has_false_non_aligned_all_true() {
1000        // 65 elements: exercises the remainder path in has_false
1001        let arr = BooleanArray::from(vec![true; 65]);
1002        assert!(arr.has_true());
1003        assert!(!arr.has_false());
1004    }
1005
1006    #[test]
1007    fn test_has_false_non_aligned_last_false() {
1008        // 64 trues + 1 false: remainder path should find the false
1009        let mut values = vec![true; 64];
1010        values.push(false);
1011        let arr = BooleanArray::from(values);
1012        assert!(arr.has_true());
1013        assert!(arr.has_false());
1014    }
1015
1016    #[test]
1017    fn test_has_false_exact_64_all_true() {
1018        // Exactly 64 elements, no remainder
1019        let arr = BooleanArray::from(vec![true; 64]);
1020        assert!(arr.has_true());
1021        assert!(!arr.has_false());
1022    }
1023
1024    #[test]
1025    fn test_has_true_has_false_unaligned_slices() {
1026        let cases = [
1027            (1, 129, true, false),
1028            (3, 130, true, false),
1029            (5, 65, true, false),
1030            (7, 64, true, false),
1031        ];
1032
1033        let base = BooleanArray::from(vec![true; 300]);
1034
1035        for (offset, len, expected_has_true, expected_has_false) in cases {
1036            let arr = base.slice(offset, len);
1037            assert_eq!(
1038                arr.has_true(),
1039                expected_has_true,
1040                "offset={offset} len={len}"
1041            );
1042            assert_eq!(
1043                arr.has_false(),
1044                expected_has_false,
1045                "offset={offset} len={len}"
1046            );
1047        }
1048    }
1049
1050    #[test]
1051    fn test_has_true_has_false_exact_multiples_of_64() {
1052        let cases = [
1053            (64, true, false),
1054            (128, true, false),
1055            (192, true, false),
1056            (256, true, false),
1057        ];
1058
1059        for (len, expected_has_true, expected_has_false) in cases {
1060            let arr = BooleanArray::from(vec![true; len]);
1061            assert_eq!(arr.has_true(), expected_has_true, "len={len}");
1062            assert_eq!(arr.has_false(), expected_has_false, "len={len}");
1063        }
1064    }
1065}