use crate::builder::{ArrayBuilder, BooleanBufferBuilder};
use crate::{ArrayRef, BooleanArray};
use arrow_buffer::Buffer;
use arrow_buffer::NullBufferBuilder;
use arrow_data::ArrayData;
use arrow_schema::{ArrowError, DataType};
use std::any::Any;
use std::sync::Arc;
#[derive(Debug)]
pub struct BooleanBuilder {
values_builder: BooleanBufferBuilder,
null_buffer_builder: NullBufferBuilder,
}
impl Default for BooleanBuilder {
fn default() -> Self {
Self::new()
}
}
impl BooleanBuilder {
pub fn new() -> Self {
Self::with_capacity(1024)
}
pub fn with_capacity(capacity: usize) -> Self {
Self {
values_builder: BooleanBufferBuilder::new(capacity),
null_buffer_builder: NullBufferBuilder::new(capacity),
}
}
pub fn capacity(&self) -> usize {
self.values_builder.capacity()
}
#[inline]
pub fn append_value(&mut self, v: bool) {
self.values_builder.append(v);
self.null_buffer_builder.append_non_null();
}
#[inline]
pub fn append_null(&mut self) {
self.null_buffer_builder.append_null();
self.values_builder.advance(1);
}
#[inline]
pub fn append_nulls(&mut self, n: usize) {
self.null_buffer_builder.append_n_nulls(n);
self.values_builder.advance(n);
}
#[inline]
pub fn append_option(&mut self, v: Option<bool>) {
match v {
None => self.append_null(),
Some(v) => self.append_value(v),
};
}
#[inline]
pub fn append_slice(&mut self, v: &[bool]) {
self.values_builder.append_slice(v);
self.null_buffer_builder.append_n_non_nulls(v.len());
}
#[inline]
pub fn append_n(&mut self, additional: usize, v: bool) {
self.values_builder.append_n(additional, v);
self.null_buffer_builder.append_n_non_nulls(additional);
}
#[inline]
pub fn append_values(&mut self, values: &[bool], is_valid: &[bool]) -> Result<(), ArrowError> {
if values.len() != is_valid.len() {
Err(ArrowError::InvalidArgumentError(
"Value and validity lengths must be equal".to_string(),
))
} else {
self.null_buffer_builder.append_slice(is_valid);
self.values_builder.append_slice(values);
Ok(())
}
}
pub fn finish(&mut self) -> BooleanArray {
let len = self.len();
let null_bit_buffer = self.null_buffer_builder.finish();
let builder = ArrayData::builder(DataType::Boolean)
.len(len)
.add_buffer(self.values_builder.finish().into_inner())
.nulls(null_bit_buffer);
let array_data = unsafe { builder.build_unchecked() };
BooleanArray::from(array_data)
}
pub fn finish_cloned(&self) -> BooleanArray {
let len = self.len();
let nulls = self.null_buffer_builder.finish_cloned();
let value_buffer = Buffer::from_slice_ref(self.values_builder.as_slice());
let builder = ArrayData::builder(DataType::Boolean)
.len(len)
.add_buffer(value_buffer)
.nulls(nulls);
let array_data = unsafe { builder.build_unchecked() };
BooleanArray::from(array_data)
}
pub fn values_slice(&self) -> &[u8] {
self.values_builder.as_slice()
}
pub fn validity_slice(&self) -> Option<&[u8]> {
self.null_buffer_builder.as_slice()
}
}
impl ArrayBuilder for BooleanBuilder {
fn as_any(&self) -> &dyn Any {
self
}
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn len(&self) -> usize {
self.values_builder.len()
}
fn finish(&mut self) -> ArrayRef {
Arc::new(self.finish())
}
fn finish_cloned(&self) -> ArrayRef {
Arc::new(self.finish_cloned())
}
}
impl Extend<Option<bool>> for BooleanBuilder {
#[inline]
fn extend<T: IntoIterator<Item = Option<bool>>>(&mut self, iter: T) {
for v in iter {
self.append_option(v)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Array;
#[test]
fn test_boolean_array_builder() {
let buf = Buffer::from([72_u8, 2_u8]);
let mut builder = BooleanArray::builder(10);
for i in 0..10 {
if i == 3 || i == 6 || i == 9 {
builder.append_value(true);
} else {
builder.append_value(false);
}
}
let arr = builder.finish();
assert_eq!(&buf, arr.values().inner());
assert_eq!(10, arr.len());
assert_eq!(0, arr.offset());
assert_eq!(0, arr.null_count());
for i in 0..10 {
assert!(!arr.is_null(i));
assert!(arr.is_valid(i));
assert_eq!(i == 3 || i == 6 || i == 9, arr.value(i), "failed at {i}")
}
}
#[test]
fn test_boolean_array_builder_append_slice() {
let arr1 = BooleanArray::from(vec![Some(true), Some(false), None, None, Some(false)]);
let mut builder = BooleanArray::builder(0);
builder.append_slice(&[true, false]);
builder.append_null();
builder.append_null();
builder.append_value(false);
let arr2 = builder.finish();
assert_eq!(arr1, arr2);
}
#[test]
fn test_boolean_array_builder_append_slice_large() {
let arr1 = BooleanArray::from(vec![true; 513]);
let mut builder = BooleanArray::builder(512);
builder.append_slice(&[true; 513]);
let arr2 = builder.finish();
assert_eq!(arr1, arr2);
}
#[test]
fn test_boolean_array_builder_no_null() {
let mut builder = BooleanArray::builder(0);
builder.append_option(Some(true));
builder.append_value(false);
builder.append_slice(&[true, false, true]);
builder
.append_values(&[false, false, true], &[true, true, true])
.unwrap();
let array = builder.finish();
assert_eq!(0, array.null_count());
assert!(array.nulls().is_none());
}
#[test]
fn test_boolean_array_builder_finish_cloned() {
let mut builder = BooleanArray::builder(16);
builder.append_option(Some(true));
builder.append_value(false);
builder.append_slice(&[true, false, true]);
let mut array = builder.finish_cloned();
assert_eq!(3, array.true_count());
assert_eq!(2, array.false_count());
builder
.append_values(&[false, false, true], &[true, true, true])
.unwrap();
array = builder.finish();
assert_eq!(4, array.true_count());
assert_eq!(4, array.false_count());
assert_eq!(0, array.null_count());
assert!(array.nulls().is_none());
}
#[test]
fn test_extend() {
let mut builder = BooleanBuilder::new();
builder.extend([false, false, true, false, false].into_iter().map(Some));
builder.extend([true, true, false].into_iter().map(Some));
let array = builder.finish();
let values = array.iter().map(|x| x.unwrap()).collect::<Vec<_>>();
assert_eq!(
&values,
&[false, false, true, false, false, true, true, false]
)
}
#[test]
fn test_boolean_array_builder_append_n() {
let mut builder = BooleanBuilder::new();
builder.append_n(3, true);
builder.append_n(2, false);
let array = builder.finish();
assert_eq!(3, array.true_count());
assert_eq!(2, array.false_count());
assert_eq!(0, array.null_count());
let values = array.iter().map(|x| x.unwrap()).collect::<Vec<_>>();
assert_eq!(&values, &[true, true, true, false, false])
}
}