reifydb_value/value/container/
bool_array.rs1use arrow_array::{Array, BooleanArray};
5use arrow_buffer::{BooleanBuffer, NullBuffer};
6use arrow_select::filter::FilterPredicate;
7
8use crate::{
9 Result,
10 util::{bitmap, kernel},
11 value::{Value, value_type::ValueType},
12};
13
14pub fn get_value(array: &BooleanArray, index: usize) -> Value {
15 if index < array.len() {
16 Value::Boolean(array.value(index))
17 } else {
18 Value::none_of(ValueType::Boolean)
19 }
20}
21
22pub fn as_string(array: &BooleanArray, index: usize) -> String {
23 if index < array.len() {
24 array.value(index).to_string()
25 } else {
26 "none".to_string()
27 }
28}
29
30pub fn slice(array: &BooleanArray, start: usize, end: usize) -> BooleanArray {
31 BooleanArray::new(
32 bitmap::slice(array.values(), start, end),
33 bitmap::slice_nulls(array.logical_nulls().as_ref(), start, end),
34 )
35}
36
37pub fn take(array: &BooleanArray, num: usize) -> BooleanArray {
38 slice(array, 0, num)
39}
40
41pub fn filter(array: &BooleanArray, mask: &BooleanBuffer) -> BooleanArray {
42 filter_with(array, &kernel::predicate(mask, array.len()))
43}
44
45pub fn filter_with(array: &BooleanArray, predicate: &FilterPredicate) -> BooleanArray {
46 let selected = kernel::filtered(array, predicate);
47 let nulls = kernel::kept_nulls(array, &selected);
48 BooleanArray::new(selected.into_parts().0, nulls)
49}
50
51pub fn reorder(array: &BooleanArray, indices: &[usize]) -> Result<BooleanArray> {
52 kernel::rows_in_range(indices, array.len())?;
53 Ok(BooleanArray::new(
54 bitmap::reorder(array.values(), indices),
55 bitmap::reorder_nulls(array.logical_nulls().as_ref(), indices),
56 ))
57}
58
59pub fn attach_nulls(array: BooleanArray, nulls: Option<NullBuffer>) -> BooleanArray {
60 bitmap::assert_nulls_len(nulls.as_ref(), array.len());
61 let (values, _) = array.into_parts();
62 BooleanArray::new(values, nulls)
63}
64
65pub fn capacity(array: &BooleanArray) -> usize {
66 let buffer = array.values().inner();
67 if buffer.strong_count() == 1 {
68 buffer.capacity() * 8
69 } else {
70 array.len()
71 }
72}
73
74pub fn heap_size(array: &BooleanArray) -> usize {
75 capacity(array).div_ceil(8)
76}
77
78#[cfg(test)]
79mod tests {
80 use arrow_array::BooleanArray;
81
82 use super::{as_string, filter, get_value, reorder, slice, take};
83 use crate::value::{Value, value_type::ValueType};
84
85 fn values(array: &BooleanArray) -> Vec<bool> {
86 array.values().iter().collect()
87 }
88
89 #[test]
90 fn get_value_and_as_string_past_the_end_read_as_none() {
91 let array = BooleanArray::from(vec![true, false]);
93 assert_eq!(get_value(&array, 1), Value::Boolean(false));
94 assert_eq!(get_value(&array, 2), Value::none_of(ValueType::Boolean));
95 assert_eq!(as_string(&array, 0), "true");
96 assert_eq!(as_string(&array, 2), "none");
97 }
98
99 #[test]
100 fn slice_and_take_clamp_like_the_old_container() {
101 let array = BooleanArray::from(vec![true, false, true, false]);
103 assert_eq!(values(&slice(&array, 1, 3)), vec![false, true]);
104 assert_eq!(values(&slice(&array, 2, 40)), vec![true, false]);
105 assert_eq!(slice(&array, 3, 1).len(), 0);
106 assert_eq!(take(&array, 9).len(), 4);
107 }
108
109 #[test]
110 fn filter_ignores_a_long_mask_and_reorder_refuses_an_out_of_range_row() {
111 let array = BooleanArray::from(vec![true, false, true]);
113 let mask = BooleanArray::from(vec![true, false, true, true, true]);
114 assert_eq!(values(&filter(&array, mask.values())), vec![true, true]);
115 let error = reorder(&array, &[2, 7, 1]).unwrap_err();
116 assert_eq!(error.diagnostic().message, "row index 7 out of range for a column of 3 rows");
117 }
118}