Skip to main content

arrow_select/
zip.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
18//! [`zip`]: Combine values from two arrays based on boolean mask
19
20use crate::filter::{SlicesIterator, prep_null_mask_filter};
21use arrow_array::cast::AsArray;
22use arrow_array::types::{
23    BinaryType, BinaryViewType, ByteArrayType, ByteViewType, LargeBinaryType, LargeUtf8Type,
24    StringViewType, Utf8Type,
25};
26use arrow_array::*;
27use arrow_buffer::{
28    ArrowNativeType, BooleanBuffer, Buffer, MutableBuffer, NullBuffer, OffsetBuffer, ScalarBuffer,
29    ToByteSlice,
30};
31use arrow_data::transform::MutableArrayData;
32use arrow_data::{ArrayData, ByteView};
33use arrow_schema::{ArrowError, DataType};
34use std::fmt::{Debug, Formatter};
35use std::hash::Hash;
36use std::marker::PhantomData;
37use std::ops::Not;
38use std::sync::{Arc, OnceLock};
39
40/// Zip two arrays by some boolean mask.
41///
42/// - Where `mask` is `true`, values of `truthy` are taken
43/// - Where `mask` is `false` or `NULL`, values of `falsy` are taken
44///
45/// # Example: `zip` two arrays
46/// ```
47/// # use std::sync::Arc;
48/// # use arrow_array::{ArrayRef, BooleanArray, Int32Array};
49/// # use arrow_select::zip::zip;
50/// // mask: [true, true, false, NULL, true]
51/// let mask = BooleanArray::from(vec![
52///   Some(true), Some(true), Some(false), None, Some(true)
53/// ]);
54/// // truthy array: [1, NULL, 3, 4, 5]
55/// let truthy = Int32Array::from(vec![
56///   Some(1), None, Some(3), Some(4), Some(5)
57/// ]);
58/// // falsy array: [10, 20, 30, 40, 50]
59/// let falsy = Int32Array::from(vec![
60///   Some(10), Some(20), Some(30), Some(40), Some(50)
61/// ]);
62/// // zip with this mask select the first, second and last value from `truthy`
63/// // and the third and fourth value from `falsy`
64/// let result = zip(&mask, &truthy, &falsy).unwrap();
65/// // Expected: [1, NULL, 30, 40, 5]
66/// let expected: ArrayRef = Arc::new(Int32Array::from(vec![
67///   Some(1), None, Some(30), Some(40), Some(5)
68/// ]));
69/// assert_eq!(&result, &expected);
70/// ```
71///
72/// # Example: `zip` and array with a scalar
73///
74/// Use `zip` to replace certain values in an array with a scalar
75///
76/// ```
77/// # use std::sync::Arc;
78/// # use arrow_array::{ArrayRef, BooleanArray, Int32Array};
79/// # use arrow_select::zip::zip;
80/// // mask: [true, true, false, NULL, true]
81/// let mask = BooleanArray::from(vec![
82///   Some(true), Some(true), Some(false), None, Some(true)
83/// ]);
84/// //  array: [1, NULL, 3, 4, 5]
85/// let arr = Int32Array::from(vec![
86///   Some(1), None, Some(3), Some(4), Some(5)
87/// ]);
88/// // scalar: 42
89/// let scalar = Int32Array::new_scalar(42);
90/// // zip the array with the  mask select the first, second and last value from `arr`
91/// // and fill the third and fourth value with the scalar 42
92/// let result = zip(&mask, &arr, &scalar).unwrap();
93/// // Expected: [1, NULL, 42, 42, 5]
94/// let expected: ArrayRef = Arc::new(Int32Array::from(vec![
95///   Some(1), None, Some(42), Some(42), Some(5)
96/// ]));
97/// assert_eq!(&result, &expected);
98/// ```
99pub fn zip(
100    mask: &BooleanArray,
101    truthy: &dyn Datum,
102    falsy: &dyn Datum,
103) -> Result<ArrayRef, ArrowError> {
104    let (truthy_array, truthy_is_scalar) = truthy.get();
105    let (falsy_array, falsy_is_scalar) = falsy.get();
106
107    if falsy_is_scalar && truthy_is_scalar {
108        let zipper = ScalarZipper::try_new(truthy, falsy)?;
109        return zipper.zip_impl.create_output(mask);
110    }
111
112    let truthy = truthy_array;
113    let falsy = falsy_array;
114
115    if truthy.data_type() != falsy.data_type() {
116        return Err(ArrowError::InvalidArgumentError(
117            "arguments need to have the same data type".into(),
118        ));
119    }
120
121    if truthy_is_scalar && truthy.len() != 1 {
122        return Err(ArrowError::InvalidArgumentError(
123            "scalar arrays must have 1 element".into(),
124        ));
125    }
126    if !truthy_is_scalar && truthy.len() != mask.len() {
127        return Err(ArrowError::InvalidArgumentError(
128            "all arrays should have the same length".into(),
129        ));
130    }
131    if falsy_is_scalar && falsy.len() != 1 {
132        return Err(ArrowError::InvalidArgumentError(
133            "scalar arrays must have 1 element".into(),
134        ));
135    }
136    if !falsy_is_scalar && falsy.len() != mask.len() {
137        return Err(ArrowError::InvalidArgumentError(
138            "all arrays should have the same length".into(),
139        ));
140    }
141
142    let falsy = falsy.to_data();
143    let truthy = truthy.to_data();
144
145    zip_impl(mask, &truthy, truthy_is_scalar, &falsy, falsy_is_scalar)
146}
147
148fn count_true_runs(mask: &BooleanBuffer) -> usize {
149    let mut slices = 0;
150    let mut previous = 0;
151    for chunk in mask.bit_chunks().iter_padded() {
152        let starts = chunk & !((chunk << 1) | previous);
153        slices += starts.count_ones() as usize;
154        previous = chunk >> 63;
155    }
156    slices
157}
158
159fn should_use_interleave(mask: &BooleanBuffer) -> bool {
160    const MIN_LEN: usize = 1024;
161
162    // Interleave's fixed dispatch and index construction costs are not competitive
163    // for small arrays. For larger arrays, use the run count that determines the
164    // amount of work performed by the MutableArrayData implementation.
165    mask.len() >= MIN_LEN && count_true_runs(mask) > mask.len() / 8
166}
167
168fn interleave_arrays(
169    mask: &BooleanBuffer,
170    truthy: &ArrayData,
171    falsy: &ArrayData,
172) -> Result<ArrayRef, ArrowError> {
173    let truthy = make_array(truthy.clone());
174    let falsy = make_array(falsy.clone());
175    let indices: Vec<_> = mask
176        .iter()
177        .enumerate()
178        .map(|(idx, selected)| (usize::from(!selected), idx))
179        .collect();
180    crate::interleave::interleave(&[truthy.as_ref(), falsy.as_ref()], &indices)
181}
182
183fn zip_impl(
184    mask: &BooleanArray,
185    truthy: &ArrayData,
186    truthy_is_scalar: bool,
187    falsy: &ArrayData,
188    falsy_is_scalar: bool,
189) -> Result<ArrayRef, ArrowError> {
190    let mask_buffer = maybe_prep_null_mask_filter(mask);
191    if !truthy_is_scalar && !falsy_is_scalar && should_use_interleave(&mask_buffer) {
192        return interleave_arrays(&mask_buffer, truthy, falsy);
193    }
194
195    let mut mutable = MutableArrayData::new(vec![truthy, falsy], false, truthy.len());
196
197    // the SlicesIterator slices only the true values. So the gaps left by this iterator we need to
198    // fill with falsy values
199
200    // keep track of how much is filled
201    let mut filled = 0;
202
203    for (start, end) in SlicesIterator::from(&mask_buffer) {
204        // the gap needs to be filled with falsy values
205        if start > filled {
206            if falsy_is_scalar {
207                for _ in filled..start {
208                    // Copy the first item from the 'falsy' array into the output buffer.
209                    mutable.try_extend(1, 0, 1)?;
210                }
211            } else {
212                mutable.try_extend(1, filled, start)?;
213            }
214        }
215        // fill with truthy values
216        if truthy_is_scalar {
217            for _ in start..end {
218                // Copy the first item from the 'truthy' array into the output buffer.
219                mutable.try_extend(0, 0, 1)?;
220            }
221        } else {
222            mutable.try_extend(0, start, end)?;
223        }
224        filled = end;
225    }
226    // the remaining part is falsy
227    if filled < mask.len() {
228        if falsy_is_scalar {
229            for _ in filled..mask.len() {
230                // Copy the first item from the 'falsy' array into the output buffer.
231                mutable.try_extend(1, 0, 1)?;
232            }
233        } else {
234            mutable.try_extend(1, filled, mask.len())?;
235        }
236    }
237
238    let data = mutable.freeze();
239    Ok(make_array(data))
240}
241
242/// Zipper for 2 scalars
243///
244/// Useful for using in `IF <expr> THEN <scalar> ELSE <scalar> END` expressions
245///
246/// # Example
247/// ```
248/// # use std::sync::Arc;
249/// # use arrow_array::{ArrayRef, BooleanArray, Int32Array, Scalar, cast::AsArray, types::Int32Type};
250///
251/// # use arrow_select::zip::ScalarZipper;
252/// let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
253/// let scalar_falsy = Scalar::new(Int32Array::from_value(123, 1));
254/// let zipper = ScalarZipper::try_new(&scalar_truthy, &scalar_falsy).unwrap();
255///
256/// // Later when we have a boolean mask
257/// let mask = BooleanArray::from(vec![true, false, true, false, true]);
258/// let result = zipper.zip(&mask).unwrap();
259/// let actual = result.as_primitive::<Int32Type>();
260/// let expected = Int32Array::from(vec![Some(42), Some(123), Some(42), Some(123), Some(42)]);
261/// ```
262///
263#[derive(Debug, Clone)]
264pub struct ScalarZipper {
265    zip_impl: Arc<dyn ZipImpl>,
266}
267
268impl ScalarZipper {
269    /// Try to create a new ScalarZipper from two scalar Datum
270    ///
271    /// # Errors
272    /// returns error if:
273    /// - the two Datum have different data types
274    /// - either Datum is not a scalar (or has more than 1 element)
275    ///
276    pub fn try_new(truthy: &dyn Datum, falsy: &dyn Datum) -> Result<Self, ArrowError> {
277        let (truthy, truthy_is_scalar) = truthy.get();
278        let (falsy, falsy_is_scalar) = falsy.get();
279
280        if truthy.data_type() != falsy.data_type() {
281            return Err(ArrowError::InvalidArgumentError(
282                "arguments need to have the same data type".into(),
283            ));
284        }
285
286        if !truthy_is_scalar {
287            return Err(ArrowError::InvalidArgumentError(
288                "only scalar arrays are supported".into(),
289            ));
290        }
291
292        if !falsy_is_scalar {
293            return Err(ArrowError::InvalidArgumentError(
294                "only scalar arrays are supported".into(),
295            ));
296        }
297
298        if truthy.len() != 1 {
299            return Err(ArrowError::InvalidArgumentError(
300                "scalar arrays must have 1 element".into(),
301            ));
302        }
303        if falsy.len() != 1 {
304            return Err(ArrowError::InvalidArgumentError(
305                "scalar arrays must have 1 element".into(),
306            ));
307        }
308
309        macro_rules! primitive_size_helper {
310            ($t:ty) => {
311                Arc::new(PrimitiveScalarImpl::<$t>::new(truthy, falsy)) as Arc<dyn ZipImpl>
312            };
313        }
314
315        let zip_impl = downcast_primitive! {
316            truthy.data_type() => (primitive_size_helper),
317            DataType::Utf8 => {
318                Arc::new(BytesScalarImpl::<Utf8Type>::new(truthy, falsy)) as Arc<dyn ZipImpl>
319            },
320            DataType::LargeUtf8 => {
321                Arc::new(BytesScalarImpl::<LargeUtf8Type>::new(truthy, falsy)) as Arc<dyn ZipImpl>
322            },
323            DataType::Binary => {
324                Arc::new(BytesScalarImpl::<BinaryType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
325            },
326            DataType::LargeBinary => {
327                Arc::new(BytesScalarImpl::<LargeBinaryType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
328            },
329            DataType::Utf8View => {
330                Arc::new(ByteViewScalarImpl::<StringViewType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
331            },
332            DataType::BinaryView => {
333                Arc::new(ByteViewScalarImpl::<BinaryViewType>::new(truthy, falsy)) as Arc<dyn ZipImpl>
334            },
335            _ => {
336                Arc::new(FallbackImpl::new(truthy, falsy)) as Arc<dyn ZipImpl>
337            },
338        };
339
340        Ok(Self { zip_impl })
341    }
342
343    /// Creating output array based on input boolean array and the two scalar values the zipper was created with
344    /// See struct level documentation for examples.
345    pub fn zip(&self, mask: &BooleanArray) -> Result<ArrayRef, ArrowError> {
346        self.zip_impl.create_output(mask)
347    }
348}
349
350/// Impl for creating output array based on a mask
351trait ZipImpl: Debug + Send + Sync {
352    /// Creating output array based on input boolean array
353    fn create_output(&self, input: &BooleanArray) -> Result<ArrayRef, ArrowError>;
354}
355
356#[derive(Debug, PartialEq)]
357struct FallbackImpl {
358    truthy: ArrayData,
359    falsy: ArrayData,
360}
361
362impl FallbackImpl {
363    fn new(left: &dyn Array, right: &dyn Array) -> Self {
364        Self {
365            truthy: left.to_data(),
366            falsy: right.to_data(),
367        }
368    }
369}
370
371impl ZipImpl for FallbackImpl {
372    fn create_output(&self, predicate: &BooleanArray) -> Result<ArrayRef, ArrowError> {
373        zip_impl(predicate, &self.truthy, true, &self.falsy, true)
374    }
375}
376
377struct PrimitiveScalarImpl<T: ArrowPrimitiveType> {
378    data_type: DataType,
379    truthy: Option<T::Native>,
380    falsy: Option<T::Native>,
381}
382
383impl<T: ArrowPrimitiveType> Debug for PrimitiveScalarImpl<T> {
384    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
385        f.debug_struct("PrimitiveScalarImpl")
386            .field("data_type", &self.data_type)
387            .field("truthy", &self.truthy)
388            .field("falsy", &self.falsy)
389            .finish()
390    }
391}
392
393impl<T: ArrowPrimitiveType> PrimitiveScalarImpl<T> {
394    fn new(truthy: &dyn Array, falsy: &dyn Array) -> Self {
395        Self {
396            data_type: truthy.data_type().clone(),
397            truthy: Self::get_value_from_scalar(truthy),
398            falsy: Self::get_value_from_scalar(falsy),
399        }
400    }
401
402    fn get_value_from_scalar(scalar: &dyn Array) -> Option<T::Native> {
403        if scalar.is_null(0) {
404            None
405        } else {
406            let value = scalar.as_primitive::<T>().value(0);
407
408            Some(value)
409        }
410    }
411
412    /// return an output array that has
413    /// `value` in all locations where predicate is true
414    /// `null` otherwise
415    fn get_scalar_and_null_buffer_for_single_non_nullable(
416        predicate: BooleanBuffer,
417        value: T::Native,
418    ) -> (Vec<T::Native>, Option<NullBuffer>) {
419        let result_len = predicate.len();
420        let nulls = NullBuffer::new(predicate);
421        let scalars = vec![value; result_len];
422
423        (scalars, Some(nulls))
424    }
425}
426
427impl<T: ArrowPrimitiveType> ZipImpl for PrimitiveScalarImpl<T> {
428    fn create_output(&self, predicate: &BooleanArray) -> Result<ArrayRef, ArrowError> {
429        let result_len = predicate.len();
430        // Nulls are treated as false
431        let predicate = maybe_prep_null_mask_filter(predicate);
432
433        let (scalars, nulls): (Vec<T::Native>, Option<NullBuffer>) = match (self.truthy, self.falsy)
434        {
435            (Some(truthy_val), Some(falsy_val)) => {
436                let scalars: Vec<T::Native> = predicate
437                    .iter()
438                    .map(|b| if b { truthy_val } else { falsy_val })
439                    .collect();
440
441                (scalars, None)
442            }
443            (Some(truthy_val), None) => {
444                // If a value is true we need the TRUTHY and the null buffer will have 1 (meaning not null)
445                // If a value is false we need the FALSY and the null buffer will have 0 (meaning null)
446
447                Self::get_scalar_and_null_buffer_for_single_non_nullable(predicate, truthy_val)
448            }
449            (None, Some(falsy_val)) => {
450                // Flipping the boolean buffer as we want the opposite of the TRUE case
451                //
452                // if the condition is true we want null so we need to NOT the value so we get 0 (meaning null)
453                // if the condition is false we want the FALSY value so we need to NOT the value so we get 1 (meaning not null)
454                let predicate = predicate.not();
455
456                Self::get_scalar_and_null_buffer_for_single_non_nullable(predicate, falsy_val)
457            }
458            (None, None) => {
459                // All values are null
460                let nulls = NullBuffer::new_null(result_len);
461                let scalars = vec![T::default_value(); result_len];
462
463                (scalars, Some(nulls))
464            }
465        };
466
467        let scalars = ScalarBuffer::<T::Native>::from(scalars);
468        let output = PrimitiveArray::<T>::try_new(scalars, nulls)?;
469
470        // Keep decimal precisions, scales or timestamps timezones
471        let output = output.with_data_type(self.data_type.clone());
472
473        Ok(Arc::new(output))
474    }
475}
476
477#[derive(PartialEq, Hash)]
478struct BytesScalarImpl<T: ByteArrayType> {
479    truthy: Option<Vec<u8>>,
480    falsy: Option<Vec<u8>>,
481    phantom: PhantomData<T>,
482}
483
484impl<T: ByteArrayType> Debug for BytesScalarImpl<T> {
485    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
486        f.debug_struct("BytesScalarImpl")
487            .field("truthy", &self.truthy)
488            .field("falsy", &self.falsy)
489            .finish()
490    }
491}
492
493impl<T: ByteArrayType> BytesScalarImpl<T> {
494    fn new(truthy_value: &dyn Array, falsy_value: &dyn Array) -> Self {
495        Self {
496            truthy: Self::get_value_from_scalar(truthy_value),
497            falsy: Self::get_value_from_scalar(falsy_value),
498            phantom: PhantomData,
499        }
500    }
501
502    fn get_value_from_scalar(scalar: &dyn Array) -> Option<Vec<u8>> {
503        if scalar.is_null(0) {
504            None
505        } else {
506            let bytes: &[u8] = scalar.as_bytes::<T>().value(0).as_ref();
507
508            Some(bytes.to_vec())
509        }
510    }
511
512    /// return an output array that has
513    /// `value` in all locations where predicate is true
514    /// `null` otherwise
515    #[expect(clippy::type_complexity)]
516    fn get_scalar_and_null_buffer_for_single_non_nullable(
517        predicate: BooleanBuffer,
518        value: &[u8],
519    ) -> Result<(Buffer, OffsetBuffer<T::Offset>, Option<NullBuffer>), ArrowError> {
520        let value_length = value.len();
521
522        let number_of_true = predicate.count_set_bits();
523
524        // Fast path for all nulls
525        if number_of_true == 0 {
526            // All values are null
527            let nulls = NullBuffer::new_null(predicate.len());
528
529            return Ok((
530                // Empty bytes
531                Buffer::from(&[]),
532                // All nulls so all lengths are 0
533                OffsetBuffer::<T::Offset>::new_zeroed(predicate.len()),
534                Some(nulls),
535            ));
536        }
537
538        let offsets = OffsetBuffer::<T::Offset>::from_lengths(
539            predicate.iter().map(|b| if b { value_length } else { 0 }),
540        );
541
542        let mut bytes = MutableBuffer::with_capacity(0);
543        bytes
544            .try_repeat_slice_n_times(value, number_of_true)
545            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
546
547        let bytes = Buffer::from(bytes);
548
549        // If a value is true we need the TRUTHY and the null buffer will have 1 (meaning not null)
550        // If a value is false we need the FALSY and the null buffer will have 0 (meaning null)
551        let nulls = NullBuffer::new(predicate);
552
553        Ok((bytes, offsets, Some(nulls)))
554    }
555
556    /// Create a [`Buffer`] where `value` slice is repeated `number_of_values` times
557    /// and [`OffsetBuffer`] where there are `number_of_values` lengths, and all equals to `value` length
558    fn get_bytes_and_offset_for_all_same_value(
559        number_of_values: usize,
560        value: &[u8],
561    ) -> Result<(Buffer, OffsetBuffer<T::Offset>), ArrowError> {
562        let value_length = value.len();
563
564        let offsets =
565            OffsetBuffer::<T::Offset>::from_repeated_length(value_length, number_of_values);
566
567        let mut bytes = MutableBuffer::with_capacity(0);
568        bytes
569            .try_repeat_slice_n_times(value, number_of_values)
570            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
571        let bytes = Buffer::from(bytes);
572
573        Ok((bytes, offsets))
574    }
575
576    fn create_output_on_non_nulls(
577        predicate: &BooleanBuffer,
578        truthy_val: &[u8],
579        falsy_val: &[u8],
580    ) -> Result<(Buffer, OffsetBuffer<<T as ByteArrayType>::Offset>), ArrowError> {
581        let true_count = predicate.count_set_bits();
582
583        match true_count {
584            0 => {
585                // All values are falsy
586                return Self::get_bytes_and_offset_for_all_same_value(predicate.len(), falsy_val);
587            }
588            n if n == predicate.len() => {
589                // All values are truthy
590                return Self::get_bytes_and_offset_for_all_same_value(predicate.len(), truthy_val);
591            }
592
593            _ => {
594                // Fallback
595            }
596        }
597
598        let total_number_of_bytes = true_count
599            .checked_mul(truthy_val.len())
600            .and_then(|truthy_bytes| {
601                let falsy_bytes = (predicate.len() - true_count).checked_mul(falsy_val.len())?;
602                truthy_bytes.checked_add(falsy_bytes)
603            })
604            .ok_or_else(|| ArrowError::MemoryError("zip output size overflow".to_string()))?;
605        T::Offset::from_usize(total_number_of_bytes)
606            .ok_or(ArrowError::OffsetOverflowError(total_number_of_bytes))?;
607        let mut mutable = MutableBuffer::with_capacity(total_number_of_bytes);
608        let mut offsets = Vec::<T::Offset>::with_capacity(predicate.len() + 1);
609        offsets.push(T::Offset::usize_as(0));
610        let mut current_offset: usize = 0;
611
612        // keep track of how much is filled
613        let mut filled = 0;
614
615        let truthy_len = truthy_val.len();
616        let falsy_len = falsy_val.len();
617
618        // Each run's offsets are bounded by the checked total output size.
619        SlicesIterator::from(predicate).try_for_each(|(start, end)| -> Result<(), ArrowError> {
620            // the gap needs to be filled with falsy values
621            if start > filled {
622                let false_repeat_count = start - filled;
623                // Push false value `repeat_count` times
624                mutable
625                    .try_repeat_slice_n_times(falsy_val, false_repeat_count)
626                    .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
627
628                let start_offset = current_offset;
629                current_offset += falsy_len * false_repeat_count;
630                offsets.extend(
631                    (1..=false_repeat_count)
632                        .map(|index| T::Offset::usize_as(start_offset + index * falsy_len)),
633                );
634            }
635
636            let true_repeat_count = end - start;
637            // fill with truthy values
638            mutable
639                .try_repeat_slice_n_times(truthy_val, true_repeat_count)
640                .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
641
642            let start_offset = current_offset;
643            current_offset += truthy_len * true_repeat_count;
644            offsets.extend(
645                (1..=true_repeat_count)
646                    .map(|index| T::Offset::usize_as(start_offset + index * truthy_len)),
647            );
648            filled = end;
649            Ok(())
650        })?;
651        // the remaining part is falsy
652        if filled < predicate.len() {
653            let false_repeat_count = predicate.len() - filled;
654            // Copy the first item from the 'falsy' array into the output buffer.
655            mutable
656                .try_repeat_slice_n_times(falsy_val, false_repeat_count)
657                .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
658
659            let start_offset = current_offset;
660            current_offset += falsy_len * false_repeat_count;
661            offsets.extend(
662                (1..=false_repeat_count)
663                    .map(|index| T::Offset::usize_as(start_offset + index * falsy_len)),
664            );
665        }
666
667        debug_assert_eq!(current_offset, total_number_of_bytes);
668        // SAFETY: offsets start at zero, are monotonically increasing, and fit in T::Offset.
669        let offsets = unsafe { OffsetBuffer::new_unchecked(offsets.into()) };
670        Ok((mutable.into(), offsets))
671    }
672}
673
674impl<T: ByteArrayType> ZipImpl for BytesScalarImpl<T> {
675    fn create_output(&self, predicate: &BooleanArray) -> Result<ArrayRef, ArrowError> {
676        let result_len = predicate.len();
677        // Nulls are treated as false
678        let predicate = maybe_prep_null_mask_filter(predicate);
679
680        let (bytes, offsets, nulls): (Buffer, OffsetBuffer<T::Offset>, Option<NullBuffer>) =
681            match (self.truthy.as_deref(), self.falsy.as_deref()) {
682                (Some(truthy_val), Some(falsy_val)) => {
683                    let (bytes, offsets) =
684                        Self::create_output_on_non_nulls(&predicate, truthy_val, falsy_val)?;
685
686                    (bytes, offsets, None)
687                }
688                (Some(truthy_val), None) => {
689                    Self::get_scalar_and_null_buffer_for_single_non_nullable(predicate, truthy_val)?
690                }
691                (None, Some(falsy_val)) => {
692                    // Flipping the boolean buffer as we want the opposite of the TRUE case
693                    //
694                    // if the condition is true we want null so we need to NOT the value so we get 0 (meaning null)
695                    // if the condition is false we want the FALSE value so we need to NOT the value so we get 1 (meaning not null)
696                    let predicate = predicate.not();
697                    Self::get_scalar_and_null_buffer_for_single_non_nullable(predicate, falsy_val)?
698                }
699                (None, None) => {
700                    // All values are null
701                    let nulls = NullBuffer::new_null(result_len);
702
703                    (
704                        // Empty bytes
705                        Buffer::from(&[]),
706                        // All nulls so all lengths are 0
707                        OffsetBuffer::<T::Offset>::new_zeroed(predicate.len()),
708                        Some(nulls),
709                    )
710                }
711            };
712
713        let output = unsafe {
714            // Safety: the values are based on valid inputs
715            // and `try_new` is expensive for strings as it validate that the input is valid utf8
716            GenericByteArray::<T>::new_unchecked(offsets, bytes, nulls)
717        };
718
719        Ok(Arc::new(output))
720    }
721}
722
723fn maybe_prep_null_mask_filter(predicate: &BooleanArray) -> BooleanBuffer {
724    // Nulls are treated as false
725    if predicate.null_count() == 0 {
726        predicate.values().clone()
727    } else {
728        let cleaned = prep_null_mask_filter(predicate);
729        let (boolean_buffer, _) = cleaned.into_parts();
730        boolean_buffer
731    }
732}
733
734struct ByteViewScalarImpl<T: ByteViewType> {
735    truthy_view: Option<u128>,
736    truthy_buffers: Arc<[Buffer]>,
737    falsy_view: Option<u128>,
738    falsy_buffers: Arc<[Buffer]>,
739    phantom: PhantomData<T>,
740}
741
742static EMPTY_ARC: OnceLock<Arc<[Buffer]>> = OnceLock::new();
743fn empty_arc_buffers() -> Arc<[Buffer]> {
744    Arc::clone(EMPTY_ARC.get_or_init(|| Arc::new([])))
745}
746
747impl<T: ByteViewType> ByteViewScalarImpl<T> {
748    fn new(truthy: &dyn Array, falsy: &dyn Array) -> Self {
749        let (truthy_view, truthy_buffers) = Self::get_value_from_scalar(truthy);
750        let (falsy_view, falsy_buffers) = Self::get_value_from_scalar(falsy);
751        Self {
752            truthy_view,
753            truthy_buffers,
754            falsy_view,
755            falsy_buffers,
756            phantom: PhantomData,
757        }
758    }
759
760    fn get_value_from_scalar(scalar: &dyn Array) -> (Option<u128>, Arc<[Buffer]>) {
761        if scalar.is_null(0) {
762            (None, empty_arc_buffers())
763        } else {
764            let (views, buffers, _) = scalar.as_byte_view::<T>().clone().into_parts();
765            (views.first().copied(), buffers)
766        }
767    }
768
769    fn get_views_for_single_non_nullable(
770        predicate: BooleanBuffer,
771        value: u128,
772        buffers: Arc<[Buffer]>,
773    ) -> (ScalarBuffer<u128>, Arc<[Buffer]>, Option<NullBuffer>) {
774        let number_of_true = predicate.count_set_bits();
775        let number_of_values = predicate.len();
776
777        // Fast path for all nulls
778        if number_of_true == 0 {
779            // All values are null
780            return (
781                vec![0; number_of_values].into(),
782                empty_arc_buffers(),
783                Some(NullBuffer::new_null(number_of_values)),
784            );
785        }
786        let bytes = vec![value; number_of_values];
787
788        // If value is true and we want to handle the TRUTHY case, the null buffer will have 1 (meaning not null)
789        // If value is false and we want to handle the FALSY case, the null buffer will have 0 (meaning null)
790        let nulls = NullBuffer::new(predicate);
791        (bytes.into(), buffers, Some(nulls))
792    }
793
794    #[expect(clippy::type_complexity)]
795    fn get_views_for_non_nullable(
796        predicate: BooleanBuffer,
797        result_len: usize,
798        truthy_view: u128,
799        truthy_buffers: Arc<[Buffer]>,
800        falsy_view: u128,
801        falsy_buffers: Arc<[Buffer]>,
802    ) -> Result<(ScalarBuffer<u128>, Arc<[Buffer]>, Option<NullBuffer>), ArrowError> {
803        let true_count = predicate.count_set_bits();
804        match true_count {
805            0 => {
806                // all values are falsy
807                Ok((vec![falsy_view; result_len].into(), falsy_buffers, None))
808            }
809            n if n == predicate.len() => {
810                // all values are truthy
811                Ok((vec![truthy_view; result_len].into(), truthy_buffers, None))
812            }
813            _ => {
814                let true_count = predicate.count_set_bits();
815                let mut buffers: Vec<Buffer> = truthy_buffers.to_vec();
816
817                // If the falsy buffers are empty, we can use the falsy view as it is, because the value
818                // is completely inlined. Otherwise, we have non-inlined values in the buffer, and we need
819                // to recalculate the falsy view
820                let view_falsy = if falsy_buffers.is_empty() {
821                    falsy_view
822                } else {
823                    let byte_view_falsy = ByteView::from(falsy_view);
824                    let new_index_falsy_buffers =
825                        buffers.len() as u32 + byte_view_falsy.buffer_index;
826                    buffers.extend(falsy_buffers.iter().cloned());
827                    let byte_view_falsy =
828                        byte_view_falsy.with_buffer_index(new_index_falsy_buffers);
829                    byte_view_falsy.as_u128()
830                };
831
832                let total_number_of_bytes = true_count * 16 + (predicate.len() - true_count) * 16;
833                let mut mutable = MutableBuffer::new(total_number_of_bytes);
834                let mut filled = 0;
835
836                SlicesIterator::from(&predicate).try_for_each(
837                    |(start, end)| -> Result<(), ArrowError> {
838                        if start > filled {
839                            let false_repeat_count = start - filled;
840                            mutable
841                                .try_repeat_slice_n_times(
842                                    view_falsy.to_byte_slice(),
843                                    false_repeat_count,
844                                )
845                                .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
846                        }
847                        let true_repeat_count = end - start;
848                        mutable
849                            .try_repeat_slice_n_times(
850                                truthy_view.to_byte_slice(),
851                                true_repeat_count,
852                            )
853                            .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
854                        filled = end;
855                        Ok(())
856                    },
857                )?;
858
859                if filled < predicate.len() {
860                    let false_repeat_count = predicate.len() - filled;
861                    mutable
862                        .try_repeat_slice_n_times(view_falsy.to_byte_slice(), false_repeat_count)
863                        .map_err(|e| ArrowError::MemoryError(e.to_string()))?;
864                }
865
866                let bytes = Buffer::from(mutable);
867                Ok((bytes.into(), buffers.into(), None))
868            }
869        }
870    }
871}
872
873impl<T: ByteViewType> Debug for ByteViewScalarImpl<T> {
874    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
875        f.debug_struct("ByteViewScalarImpl")
876            .field("truthy", &self.truthy_view)
877            .field("falsy", &self.falsy_view)
878            .finish()
879    }
880}
881
882impl<T: ByteViewType> ZipImpl for ByteViewScalarImpl<T> {
883    fn create_output(&self, predicate: &BooleanArray) -> Result<ArrayRef, ArrowError> {
884        let result_len = predicate.len();
885        // Nulls are treated as false
886        let predicate = maybe_prep_null_mask_filter(predicate);
887
888        let (views, buffers, nulls) = match (self.truthy_view, self.falsy_view) {
889            (Some(truthy), Some(falsy)) => Self::get_views_for_non_nullable(
890                predicate,
891                result_len,
892                truthy,
893                Arc::clone(&self.truthy_buffers),
894                falsy,
895                Arc::clone(&self.falsy_buffers),
896            )?,
897            (Some(truthy), None) => Self::get_views_for_single_non_nullable(
898                predicate,
899                truthy,
900                Arc::clone(&self.truthy_buffers),
901            ),
902            (None, Some(falsy)) => {
903                let predicate = predicate.not();
904                Self::get_views_for_single_non_nullable(
905                    predicate,
906                    falsy,
907                    Arc::clone(&self.falsy_buffers),
908                )
909            }
910            (None, None) => {
911                // All values are null
912                (
913                    vec![0; result_len].into(),
914                    empty_arc_buffers(),
915                    Some(NullBuffer::new_null(result_len)),
916                )
917            }
918        };
919
920        let result = unsafe { GenericByteViewArray::<T>::new_unchecked(views, buffers, nulls) };
921        Ok(Arc::new(result))
922    }
923}
924
925#[cfg(test)]
926mod test {
927    use super::*;
928    use arrow_array::types::Int32Type;
929
930    #[test]
931    fn test_count_true_runs() {
932        let assert_runs = |values: &[bool], expected| {
933            let mask: BooleanBuffer = values.iter().copied().collect();
934            assert_eq!(count_true_runs(&mask), expected, "mask: {values:?}");
935        };
936
937        assert_runs(&[], 0);
938        assert_runs(&[false, false, false], 0);
939        assert_runs(&[true, true, true], 1);
940        assert_runs(&[true, false, true, true, false, true], 3);
941
942        // Exercise runs crossing 64-bit chunk boundaries and trailing padding.
943        let mut values = vec![false; 130];
944        values[0] = true;
945        values[63..66].fill(true);
946        values[128..].fill(true);
947        assert_runs(&values, 3);
948
949        // Exercise a non-zero bit offset, as masks may be sliced.
950        let mut offset_values = vec![false; 135];
951        offset_values[3..133].copy_from_slice(&values);
952        let offset_mask: BooleanBuffer = offset_values.into_iter().collect();
953        assert_eq!(count_true_runs(&offset_mask.slice(3, 130)), 3);
954    }
955
956    #[test]
957    fn test_should_use_interleave() {
958        let short: BooleanBuffer = (0..64).map(|i| i % 2 == 0).collect();
959        assert!(!should_use_interleave(&short));
960
961        let fragmented: BooleanBuffer = (0..8192).map(|i| i % 2 == 0).collect();
962        assert!(should_use_interleave(&fragmented));
963
964        let long_runs: BooleanBuffer = (0..8192).map(|i| i < 4096).collect();
965        assert!(!should_use_interleave(&long_runs));
966
967        let sparse: BooleanBuffer = (0..8192).map(|i| i % 10 == 0).collect();
968        assert!(!should_use_interleave(&sparse));
969
970        let dense: BooleanBuffer = (0..8192).map(|i| i % 10 != 0).collect();
971        assert!(!should_use_interleave(&dense));
972
973        let fragmented_head: BooleanBuffer = (0..8192).map(|i| i < 256 && i % 2 == 0).collect();
974        assert!(!should_use_interleave(&fragmented_head));
975
976        let fragmented_edges: BooleanBuffer = (0..8192)
977            .map(|i| !(256..7936).contains(&i) && i % 2 == 0)
978            .collect();
979        assert!(!should_use_interleave(&fragmented_edges));
980
981        // Exercise arbitrary bit offsets as masks may be sliced
982        let offset: BooleanBuffer = (0..8195).map(|i| i >= 3 && i % 2 == 1).collect();
983        assert!(should_use_interleave(&offset.slice(3, 8192)));
984    }
985
986    #[test]
987    fn test_interleave_arrays() {
988        let mask = BooleanArray::from(vec![Some(true), None, Some(true), Some(false)]);
989        let mask = maybe_prep_null_mask_filter(&mask);
990        let truthy = Int32Array::from(vec![Some(1), None, Some(3), Some(4)]).to_data();
991        let falsy = Int32Array::from(vec![Some(10), Some(20), None, Some(40)]).to_data();
992        let expected = Int32Array::from(vec![Some(1), Some(20), Some(3), Some(40)]);
993
994        let actual = interleave_arrays(&mask, &truthy, &falsy).unwrap();
995        assert_eq!(actual.as_primitive::<Int32Type>(), &expected);
996    }
997
998    #[test]
999    fn test_zip_fragmented_array_mask() {
1000        let mask: BooleanArray = (0..8192)
1001            .map(|i| match i % 3 {
1002                0 => Some(true),
1003                1 => Some(false),
1004                _ => None,
1005            })
1006            .collect();
1007        let truthy: Int32Array = (0..8192).map(|i| (i % 7 != 0).then_some(i)).collect();
1008        let falsy: Int32Array = (0..8192).map(|i| (i % 11 != 0).then_some(-i)).collect();
1009        let expected: Int32Array = (0..8192)
1010            .map(|i| {
1011                let array = if i % 3 == 0 { &truthy } else { &falsy };
1012                array.is_valid(i).then(|| array.value(i))
1013            })
1014            .collect();
1015
1016        let actual = zip(&mask, &truthy, &falsy).unwrap();
1017        assert_eq!(actual.as_primitive::<Int32Type>(), &expected);
1018    }
1019
1020    #[test]
1021    fn test_zip_kernel_one() {
1022        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1023        let b = Int32Array::from(vec![None, Some(3), Some(6), Some(7), Some(3)]);
1024        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1025        let out = zip(&mask, &a, &b).unwrap();
1026        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1027        let expected = Int32Array::from(vec![Some(5), None, Some(6), Some(7), Some(1)]);
1028        assert_eq!(actual, &expected);
1029    }
1030
1031    #[test]
1032    fn test_zip_kernel_two() {
1033        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1034        let b = Int32Array::from(vec![None, Some(3), Some(6), Some(7), Some(3)]);
1035        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1036        let out = zip(&mask, &a, &b).unwrap();
1037        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1038        let expected = Int32Array::from(vec![None, Some(3), Some(7), None, Some(3)]);
1039        assert_eq!(actual, &expected);
1040    }
1041
1042    #[test]
1043    fn test_zip_kernel_scalar_falsy_1() {
1044        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1045
1046        let fallback = Scalar::new(Int32Array::from_value(42, 1));
1047
1048        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1049        let out = zip(&mask, &a, &fallback).unwrap();
1050        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1051        let expected = Int32Array::from(vec![Some(5), None, Some(42), Some(42), Some(1)]);
1052        assert_eq!(actual, &expected);
1053    }
1054
1055    #[test]
1056    fn test_zip_kernel_scalar_falsy_2() {
1057        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1058
1059        let fallback = Scalar::new(Int32Array::from_value(42, 1));
1060
1061        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1062        let out = zip(&mask, &a, &fallback).unwrap();
1063        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1064        let expected = Int32Array::from(vec![Some(42), Some(42), Some(7), None, Some(42)]);
1065        assert_eq!(actual, &expected);
1066    }
1067
1068    #[test]
1069    fn test_zip_kernel_scalar_truthy_1() {
1070        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1071
1072        let fallback = Scalar::new(Int32Array::from_value(42, 1));
1073
1074        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1075        let out = zip(&mask, &fallback, &a).unwrap();
1076        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1077        let expected = Int32Array::from(vec![Some(42), Some(42), Some(7), None, Some(42)]);
1078        assert_eq!(actual, &expected);
1079    }
1080
1081    #[test]
1082    fn test_zip_kernel_scalar_truthy_2() {
1083        let a = Int32Array::from(vec![Some(5), None, Some(7), None, Some(1)]);
1084
1085        let fallback = Scalar::new(Int32Array::from_value(42, 1));
1086
1087        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1088        let out = zip(&mask, &fallback, &a).unwrap();
1089        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1090        let expected = Int32Array::from(vec![Some(5), None, Some(42), Some(42), Some(1)]);
1091        assert_eq!(actual, &expected);
1092    }
1093
1094    #[test]
1095    fn test_zip_kernel_scalar_both_mask_ends_with_true() {
1096        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1097        let scalar_falsy = Scalar::new(Int32Array::from_value(123, 1));
1098
1099        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1100        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1101        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1102        let expected = Int32Array::from(vec![Some(42), Some(42), Some(123), Some(123), Some(42)]);
1103        assert_eq!(actual, &expected);
1104    }
1105
1106    #[test]
1107    fn test_zip_kernel_scalar_both_mask_ends_with_false() {
1108        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1109        let scalar_falsy = Scalar::new(Int32Array::from_value(123, 1));
1110
1111        let mask = BooleanArray::from(vec![true, true, false, true, false, false]);
1112        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1113        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1114        let expected = Int32Array::from(vec![
1115            Some(42),
1116            Some(42),
1117            Some(123),
1118            Some(42),
1119            Some(123),
1120            Some(123),
1121        ]);
1122        assert_eq!(actual, &expected);
1123    }
1124
1125    #[test]
1126    fn test_zip_kernel_primitive_scalar_none_1() {
1127        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1128        let scalar_falsy = Scalar::new(Int32Array::new_null(1));
1129
1130        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1131        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1132        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1133        let expected = Int32Array::from(vec![Some(42), Some(42), None, None, Some(42)]);
1134        assert_eq!(actual, &expected);
1135    }
1136
1137    #[test]
1138    fn test_zip_kernel_primitive_scalar_none_2() {
1139        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1140        let scalar_falsy = Scalar::new(Int32Array::new_null(1));
1141
1142        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1143        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1144        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1145        let expected = Int32Array::from(vec![None, None, Some(42), Some(42), None]);
1146        assert_eq!(actual, &expected);
1147    }
1148
1149    #[test]
1150    fn test_zip_kernel_primitive_scalar_both_null() {
1151        let scalar_truthy = Scalar::new(Int32Array::new_null(1));
1152        let scalar_falsy = Scalar::new(Int32Array::new_null(1));
1153
1154        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1155        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1156        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1157        let expected = Int32Array::from(vec![None, None, None, None, None]);
1158        assert_eq!(actual, &expected);
1159    }
1160
1161    #[test]
1162    fn test_zip_primitive_array_with_nulls_is_mask_should_be_treated_as_false() {
1163        let truthy = Int32Array::from_iter_values(vec![1, 2, 3, 4, 5, 6]);
1164        let falsy = Int32Array::from_iter_values(vec![7, 8, 9, 10, 11, 12]);
1165
1166        let mask = {
1167            let booleans = BooleanBuffer::from(vec![true, true, false, true, false, false]);
1168            let nulls = NullBuffer::from(vec![
1169                true, true, true,
1170                false, // null treated as false even though in the original mask it was true
1171                true, true,
1172            ]);
1173            BooleanArray::new(booleans, Some(nulls))
1174        };
1175        let out = zip(&mask, &truthy, &falsy).unwrap();
1176        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1177        let expected = Int32Array::from(vec![
1178            Some(1),
1179            Some(2),
1180            Some(9),
1181            Some(10), // true in mask but null
1182            Some(11),
1183            Some(12),
1184        ]);
1185        assert_eq!(actual, &expected);
1186    }
1187
1188    #[test]
1189    fn test_zip_kernel_primitive_scalar_with_boolean_array_mask_with_nulls_should_be_treated_as_false()
1190     {
1191        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1192        let scalar_falsy = Scalar::new(Int32Array::from_value(123, 1));
1193
1194        let mask = {
1195            let booleans = BooleanBuffer::from(vec![true, true, false, true, false, false]);
1196            let nulls = NullBuffer::from(vec![
1197                true, true, true,
1198                false, // null treated as false even though in the original mask it was true
1199                true, true,
1200            ]);
1201            BooleanArray::new(booleans, Some(nulls))
1202        };
1203        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1204        let actual = out.as_any().downcast_ref::<Int32Array>().unwrap();
1205        let expected = Int32Array::from(vec![
1206            Some(42),
1207            Some(42),
1208            Some(123),
1209            Some(123), // true in mask but null
1210            Some(123),
1211            Some(123),
1212        ]);
1213        assert_eq!(actual, &expected);
1214    }
1215
1216    #[test]
1217    fn test_zip_string_array_with_nulls_is_mask_should_be_treated_as_false() {
1218        let truthy = StringArray::from_iter_values(vec!["1", "2", "3", "4", "5", "6"]);
1219        let falsy = StringArray::from_iter_values(vec!["7", "8", "9", "10", "11", "12"]);
1220
1221        let mask = {
1222            let booleans = BooleanBuffer::from(vec![true, true, false, true, false, false]);
1223            let nulls = NullBuffer::from(vec![
1224                true, true, true,
1225                false, // null treated as false even though in the original mask it was true
1226                true, true,
1227            ]);
1228            BooleanArray::new(booleans, Some(nulls))
1229        };
1230        let out = zip(&mask, &truthy, &falsy).unwrap();
1231        let actual = out.as_string::<i32>();
1232        let expected = StringArray::from_iter_values(vec![
1233            "1", "2", "9", "10", // true in mask but null
1234            "11", "12",
1235        ]);
1236        assert_eq!(actual, &expected);
1237    }
1238
1239    #[test]
1240    fn test_zip_kernel_large_string_scalar_with_boolean_array_mask_with_nulls_should_be_treated_as_false()
1241     {
1242        let scalar_truthy = Scalar::new(LargeStringArray::from_iter_values(["test"]));
1243        let scalar_falsy = Scalar::new(LargeStringArray::from_iter_values(["something else"]));
1244
1245        let mask = {
1246            let booleans = BooleanBuffer::from(vec![true, true, false, true, false, false]);
1247            let nulls = NullBuffer::from(vec![
1248                true, true, true,
1249                false, // null treated as false even though in the original mask it was true
1250                true, true,
1251            ]);
1252            BooleanArray::new(booleans, Some(nulls))
1253        };
1254        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1255        let actual = out.as_any().downcast_ref::<LargeStringArray>().unwrap();
1256        let expected = LargeStringArray::from_iter(vec![
1257            Some("test"),
1258            Some("test"),
1259            Some("something else"),
1260            Some("something else"), // true in mask but null
1261            Some("something else"),
1262            Some("something else"),
1263        ]);
1264        assert_eq!(actual, &expected);
1265    }
1266
1267    #[test]
1268    fn test_zip_kernel_bytes_scalar_none_1() {
1269        let scalar_truthy = Scalar::new(StringArray::from_iter_values(["hello"]));
1270        let scalar_falsy = Scalar::new(StringArray::new_null(1));
1271
1272        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1273        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1274        let actual = out.as_any().downcast_ref::<StringArray>().unwrap();
1275        let expected = StringArray::from_iter(vec![
1276            Some("hello"),
1277            Some("hello"),
1278            None,
1279            None,
1280            Some("hello"),
1281        ]);
1282        assert_eq!(actual, &expected);
1283    }
1284
1285    #[test]
1286    fn test_zip_kernel_bytes_scalar_none_2() {
1287        let scalar_truthy = Scalar::new(StringArray::new_null(1));
1288        let scalar_falsy = Scalar::new(StringArray::from_iter_values(["hello"]));
1289
1290        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1291        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1292        let actual = out.as_any().downcast_ref::<StringArray>().unwrap();
1293        let expected = StringArray::from_iter(vec![None, None, Some("hello"), Some("hello"), None]);
1294        assert_eq!(actual, &expected);
1295    }
1296
1297    #[test]
1298    fn test_zip_kernel_bytes_scalar_both() {
1299        let scalar_truthy = Scalar::new(StringArray::from_iter_values(["test"]));
1300        let scalar_falsy = Scalar::new(StringArray::from_iter_values(["something else"]));
1301
1302        // mask ends with false
1303        let mask = BooleanArray::from(vec![true, true, false, true, false, false]);
1304        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1305        let actual = out.as_any().downcast_ref::<StringArray>().unwrap();
1306        let expected = StringArray::from_iter(vec![
1307            Some("test"),
1308            Some("test"),
1309            Some("something else"),
1310            Some("test"),
1311            Some("something else"),
1312            Some("something else"),
1313        ]);
1314        assert_eq!(actual, &expected);
1315    }
1316
1317    #[test]
1318    fn test_zip_scalar_bytes_offset_overflow() {
1319        // Repeating a 64 KiB scalar 32,768 times exceeds i32::MAX.
1320        // The size must be rejected before allocating the output buffer.
1321        let value = vec![0_u8; 65_536];
1322        let large = Scalar::new(BinaryArray::from_iter_values([value.as_slice()]));
1323        let empty = Scalar::new(BinaryArray::from_iter_values([b"".as_slice()]));
1324        let mask = BooleanArray::from_iter((0..65_536).map(|i| Some(i % 2 == 0)));
1325
1326        for (truthy, falsy) in [(&large, &empty), (&empty, &large)] {
1327            assert!(matches!(
1328                zip(&mask, truthy, falsy),
1329                Err(ArrowError::OffsetOverflowError(2_147_483_648))
1330            ));
1331        }
1332    }
1333
1334    #[test]
1335    fn test_zip_scalar_bytes_only_taking_one_side() {
1336        let mask_len = 5;
1337        let all_true_mask = BooleanArray::from(vec![true; mask_len]);
1338        let all_false_mask = BooleanArray::from(vec![false; mask_len]);
1339
1340        let null_scalar = Scalar::new(StringArray::new_null(1));
1341        let non_null_scalar_1 = Scalar::new(StringArray::from_iter_values(["test"]));
1342        let non_null_scalar_2 = Scalar::new(StringArray::from_iter_values(["something else"]));
1343
1344        {
1345            // 1. Test where left is null and right is non-null
1346            //    and mask is all true
1347            let out = zip(&all_true_mask, &null_scalar, &non_null_scalar_1).unwrap();
1348            let actual = out.as_string::<i32>();
1349            let expected = StringArray::from_iter(std::iter::repeat_n(None::<&str>, mask_len));
1350            assert_eq!(actual, &expected);
1351        }
1352
1353        {
1354            // 2. Test where left is null and right is non-null
1355            //    and mask is all false
1356            let out = zip(&all_false_mask, &null_scalar, &non_null_scalar_1).unwrap();
1357            let actual = out.as_string::<i32>();
1358            let expected = StringArray::from_iter(std::iter::repeat_n(Some("test"), mask_len));
1359            assert_eq!(actual, &expected);
1360        }
1361
1362        {
1363            // 3. Test where left is non-null and right is null
1364            //    and mask is all true
1365            let out = zip(&all_true_mask, &non_null_scalar_1, &null_scalar).unwrap();
1366            let actual = out.as_string::<i32>();
1367            let expected = StringArray::from_iter(std::iter::repeat_n(Some("test"), mask_len));
1368            assert_eq!(actual, &expected);
1369        }
1370
1371        {
1372            // 4. Test where left is non-null and right is null
1373            //    and mask is all false
1374            let out = zip(&all_false_mask, &non_null_scalar_1, &null_scalar).unwrap();
1375            let actual = out.as_string::<i32>();
1376            let expected = StringArray::from_iter(std::iter::repeat_n(None::<&str>, mask_len));
1377            assert_eq!(actual, &expected);
1378        }
1379
1380        {
1381            // 5. Test where both left and right are not null
1382            //    and mask is all true
1383            let out = zip(&all_true_mask, &non_null_scalar_1, &non_null_scalar_2).unwrap();
1384            let actual = out.as_string::<i32>();
1385            let expected = StringArray::from_iter(std::iter::repeat_n(Some("test"), mask_len));
1386            assert_eq!(actual, &expected);
1387        }
1388
1389        {
1390            // 6. Test where both left and right are not null
1391            //    and mask is all false
1392            let out = zip(&all_false_mask, &non_null_scalar_1, &non_null_scalar_2).unwrap();
1393            let actual = out.as_string::<i32>();
1394            let expected =
1395                StringArray::from_iter(std::iter::repeat_n(Some("something else"), mask_len));
1396            assert_eq!(actual, &expected);
1397        }
1398
1399        {
1400            // 7. Test where both left and right are null
1401            //    and mask is random
1402            let mask = BooleanArray::from(vec![true, false, true, false, true]);
1403            let out = zip(&mask, &null_scalar, &null_scalar).unwrap();
1404            let actual = out.as_string::<i32>();
1405            let expected = StringArray::from_iter(std::iter::repeat_n(None::<&str>, mask_len));
1406            assert_eq!(actual, &expected);
1407        }
1408    }
1409
1410    #[test]
1411    fn test_scalar_zipper() {
1412        let scalar_truthy = Scalar::new(Int32Array::from_value(42, 1));
1413        let scalar_falsy = Scalar::new(Int32Array::from_value(123, 1));
1414
1415        let mask = BooleanArray::from(vec![false, false, true, true, false]);
1416
1417        let scalar_zipper = ScalarZipper::try_new(&scalar_truthy, &scalar_falsy).unwrap();
1418        let out = scalar_zipper.zip(&mask).unwrap();
1419        let actual = out.as_primitive::<Int32Type>();
1420        let expected = Int32Array::from(vec![Some(123), Some(123), Some(42), Some(42), Some(123)]);
1421        assert_eq!(actual, &expected);
1422
1423        // test with different mask length as well
1424        let mask = BooleanArray::from(vec![true, false, true]);
1425        let out = scalar_zipper.zip(&mask).unwrap();
1426        let actual = out.as_primitive::<Int32Type>();
1427        let expected = Int32Array::from(vec![Some(42), Some(123), Some(42)]);
1428        assert_eq!(actual, &expected);
1429    }
1430
1431    #[test]
1432    fn test_zip_kernel_scalar_strings() {
1433        let scalar_truthy = Scalar::new(StringArray::from(vec!["hello"]));
1434        let scalar_falsy = Scalar::new(StringArray::from(vec!["world"]));
1435
1436        let mask = BooleanArray::from(vec![true, false, true, false, true]);
1437        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1438        let actual = out.as_string::<i32>();
1439        let expected = StringArray::from(vec![
1440            Some("hello"),
1441            Some("world"),
1442            Some("hello"),
1443            Some("world"),
1444            Some("hello"),
1445        ]);
1446        assert_eq!(actual, &expected);
1447    }
1448
1449    #[test]
1450    fn test_zip_kernel_scalar_binary() {
1451        let truthy_bytes: &[u8] = b"\xFF\xFE\xFD";
1452        let falsy_bytes: &[u8] = b"world";
1453        let scalar_truthy = Scalar::new(BinaryArray::from_iter_values(
1454            // Non valid UTF8 bytes
1455            vec![truthy_bytes],
1456        ));
1457        let scalar_falsy = Scalar::new(BinaryArray::from_iter_values(vec![falsy_bytes]));
1458
1459        let mask = BooleanArray::from(vec![true, false, true, false, true]);
1460        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1461        let actual = out.as_binary::<i32>();
1462        let expected = BinaryArray::from(vec![
1463            Some(truthy_bytes),
1464            Some(falsy_bytes),
1465            Some(truthy_bytes),
1466            Some(falsy_bytes),
1467            Some(truthy_bytes),
1468        ]);
1469        assert_eq!(actual, &expected);
1470    }
1471
1472    #[test]
1473    fn test_zip_kernel_scalar_large_binary() {
1474        let truthy_bytes: &[u8] = b"hey";
1475        let falsy_bytes: &[u8] = b"world";
1476        let scalar_truthy = Scalar::new(LargeBinaryArray::from_iter_values(vec![truthy_bytes]));
1477        let scalar_falsy = Scalar::new(LargeBinaryArray::from_iter_values(vec![falsy_bytes]));
1478
1479        let mask = BooleanArray::from(vec![true, false, true, false, true]);
1480        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1481        let actual = out.as_binary::<i64>();
1482        let expected = LargeBinaryArray::from(vec![
1483            Some(truthy_bytes),
1484            Some(falsy_bytes),
1485            Some(truthy_bytes),
1486            Some(falsy_bytes),
1487            Some(truthy_bytes),
1488        ]);
1489        assert_eq!(actual, &expected);
1490    }
1491
1492    // Test to ensure that the precision and scale are kept when zipping Decimal128 data
1493    #[test]
1494    fn test_zip_decimal_with_custom_precision_and_scale() {
1495        let arr = Decimal128Array::from_iter_values([12345, 456, 7890, -123223423432432])
1496            .with_precision_and_scale(20, 2)
1497            .unwrap();
1498
1499        let arr: ArrayRef = Arc::new(arr);
1500
1501        let scalar_1 = Scalar::new(arr.slice(0, 1));
1502        let scalar_2 = Scalar::new(arr.slice(1, 1));
1503        let null_scalar = Scalar::new(new_null_array(arr.data_type(), 1));
1504        let array_1: ArrayRef = arr.slice(0, 2);
1505        let array_2: ArrayRef = arr.slice(2, 2);
1506
1507        test_zip_output_data_types_for_input(scalar_1, scalar_2, null_scalar, array_1, array_2);
1508    }
1509
1510    // Test to ensure that the timezone is kept when zipping TimestampArray data
1511    #[test]
1512    fn test_zip_timestamp_with_timezone() {
1513        let arr = TimestampSecondArray::from(vec![0, 1000, 2000, 4000])
1514            .with_timezone("+01:00".to_string());
1515
1516        let arr: ArrayRef = Arc::new(arr);
1517
1518        let scalar_1 = Scalar::new(arr.slice(0, 1));
1519        let scalar_2 = Scalar::new(arr.slice(1, 1));
1520        let null_scalar = Scalar::new(new_null_array(arr.data_type(), 1));
1521        let array_1: ArrayRef = arr.slice(0, 2);
1522        let array_2: ArrayRef = arr.slice(2, 2);
1523
1524        test_zip_output_data_types_for_input(scalar_1, scalar_2, null_scalar, array_1, array_2);
1525    }
1526
1527    fn test_zip_output_data_types_for_input(
1528        scalar_1: Scalar<ArrayRef>,
1529        scalar_2: Scalar<ArrayRef>,
1530        null_scalar: Scalar<ArrayRef>,
1531        array_1: ArrayRef,
1532        array_2: ArrayRef,
1533    ) {
1534        // non null Scalar vs non null Scalar
1535        test_zip_output_data_type(&scalar_1, &scalar_2, 10);
1536
1537        // null Scalar vs non-null Scalar (and vice versa)
1538        test_zip_output_data_type(&null_scalar, &scalar_1, 10);
1539        test_zip_output_data_type(&scalar_1, &null_scalar, 10);
1540
1541        // non-null Scalar and array (and vice versa)
1542        test_zip_output_data_type(&array_1.as_ref(), &scalar_1, array_1.len());
1543        test_zip_output_data_type(&scalar_1, &array_1.as_ref(), array_1.len());
1544
1545        // Array and null scalar (and vice versa)
1546        test_zip_output_data_type(&array_1.as_ref(), &null_scalar, array_1.len());
1547
1548        test_zip_output_data_type(&null_scalar, &array_1.as_ref(), array_1.len());
1549
1550        // Both arrays
1551        test_zip_output_data_type(&array_1.as_ref(), &array_2.as_ref(), array_1.len());
1552    }
1553
1554    fn test_zip_output_data_type(truthy: &dyn Datum, falsy: &dyn Datum, mask_length: usize) {
1555        let expected_data_type = truthy.get().0.data_type().clone();
1556        assert_eq!(&expected_data_type, falsy.get().0.data_type());
1557
1558        // Try different masks to test different paths
1559        let mask_all_true = BooleanArray::from(vec![true; mask_length]);
1560        let mask_all_false = BooleanArray::from(vec![false; mask_length]);
1561        let mask_some_true_and_false =
1562            BooleanArray::from((0..mask_length).map(|i| i % 2 == 0).collect::<Vec<bool>>());
1563
1564        for mask in [&mask_all_true, &mask_all_false, &mask_some_true_and_false] {
1565            let out = zip(mask, truthy, falsy).unwrap();
1566            assert_eq!(out.data_type(), &expected_data_type);
1567        }
1568    }
1569
1570    #[test]
1571    fn zip_scalar_fallback_impl() {
1572        let truthy_list_item_scalar = Some(vec![Some(1), None, Some(3)]);
1573        let truthy_list_array_scalar =
1574            Scalar::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1575                truthy_list_item_scalar.clone(),
1576            ]));
1577        let falsy_list_item_scalar = Some(vec![None, Some(2), Some(4)]);
1578        let falsy_list_array_scalar =
1579            Scalar::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1580                falsy_list_item_scalar.clone(),
1581            ]));
1582        let mask = BooleanArray::from(vec![true, false, true, false, false, true, false]);
1583        let out = zip(&mask, &truthy_list_array_scalar, &falsy_list_array_scalar).unwrap();
1584        let actual = out.as_list::<i32>();
1585
1586        let expected = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
1587            truthy_list_item_scalar.clone(),
1588            falsy_list_item_scalar.clone(),
1589            truthy_list_item_scalar.clone(),
1590            falsy_list_item_scalar.clone(),
1591            falsy_list_item_scalar.clone(),
1592            truthy_list_item_scalar.clone(),
1593            falsy_list_item_scalar.clone(),
1594        ]);
1595        assert_eq!(actual, &expected);
1596    }
1597
1598    #[test]
1599    fn test_zip_kernel_scalar_strings_array_view() {
1600        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1601        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1602
1603        let mask = BooleanArray::from(vec![true, false, true, false]);
1604        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1605        let actual = out.as_string_view();
1606        let expected = StringViewArray::from(vec![
1607            Some("hello"),
1608            Some("world"),
1609            Some("hello"),
1610            Some("world"),
1611        ]);
1612        assert_eq!(actual, &expected);
1613    }
1614
1615    #[test]
1616    fn test_zip_kernel_scalar_binary_array_view() {
1617        let scalar_truthy = Scalar::new(BinaryViewArray::from_iter_values(vec![b"hello"]));
1618        let scalar_falsy = Scalar::new(BinaryViewArray::from_iter_values(vec![b"world"]));
1619
1620        let mask = BooleanArray::from(vec![true, false]);
1621        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1622        let actual = out.as_byte_view();
1623        let expected = BinaryViewArray::from_iter_values(vec![b"hello", b"world"]);
1624        assert_eq!(actual, &expected);
1625    }
1626
1627    #[test]
1628    fn test_zip_kernel_scalar_strings_array_view_with_nulls() {
1629        let scalar_truthy = Scalar::new(StringViewArray::from_iter_values(["hello"]));
1630        let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1631
1632        let mask = BooleanArray::from(vec![true, true, false, false, true]);
1633        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1634        let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1635        let expected = StringViewArray::from_iter(vec![
1636            Some("hello"),
1637            Some("hello"),
1638            None,
1639            None,
1640            Some("hello"),
1641        ]);
1642        assert_eq!(actual, &expected);
1643    }
1644
1645    #[test]
1646    fn test_zip_kernel_scalar_strings_array_view_all_true_null() {
1647        let scalar_truthy = Scalar::new(StringViewArray::new_null(1));
1648        let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1649        let mask = BooleanArray::from(vec![true, true]);
1650        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1651        let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1652        let expected = StringViewArray::from_iter(vec![None::<String>, None]);
1653        assert_eq!(actual, &expected);
1654    }
1655
1656    #[test]
1657    fn test_zip_kernel_scalar_strings_array_view_all_false_null() {
1658        let scalar_truthy = Scalar::new(StringViewArray::new_null(1));
1659        let scalar_falsy = Scalar::new(StringViewArray::new_null(1));
1660        let mask = BooleanArray::from(vec![false, false]);
1661        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1662        let actual = out.as_any().downcast_ref::<StringViewArray>().unwrap();
1663        let expected = StringViewArray::from_iter(vec![None::<String>, None]);
1664        assert_eq!(actual, &expected);
1665    }
1666
1667    #[test]
1668    fn test_zip_kernel_scalar_string_array_view_all_true() {
1669        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1670        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1671
1672        let mask = BooleanArray::from(vec![true, true]);
1673        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1674        let actual = out.as_string_view();
1675        let expected = StringViewArray::from(vec![Some("hello"), Some("hello")]);
1676        assert_eq!(actual, &expected);
1677    }
1678
1679    #[test]
1680    fn test_zip_kernel_scalar_string_array_view_all_false() {
1681        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1682        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["world"]));
1683
1684        let mask = BooleanArray::from(vec![false, false]);
1685        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1686        let actual = out.as_string_view();
1687        let expected = StringViewArray::from(vec![Some("world"), Some("world")]);
1688        assert_eq!(actual, &expected);
1689    }
1690
1691    #[test]
1692    fn test_zip_kernel_scalar_strings_large_strings() {
1693        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1694        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1695
1696        let mask = BooleanArray::from(vec![true, false]);
1697        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1698        let actual = out.as_string_view();
1699        let expected = StringViewArray::from(vec![
1700            Some("longer than 12 bytes"),
1701            Some("another longer than 12 bytes"),
1702        ]);
1703        assert_eq!(actual, &expected);
1704    }
1705
1706    #[test]
1707    fn test_zip_kernel_scalar_strings_array_view_large_short_strings() {
1708        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["hello"]));
1709        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1710
1711        let mask = BooleanArray::from(vec![true, false, true, false]);
1712        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1713        let actual = out.as_string_view();
1714        let expected = StringViewArray::from(vec![
1715            Some("hello"),
1716            Some("longer than 12 bytes"),
1717            Some("hello"),
1718            Some("longer than 12 bytes"),
1719        ]);
1720        assert_eq!(actual, &expected);
1721    }
1722    #[test]
1723    fn test_zip_kernel_scalar_strings_array_view_large_all_true() {
1724        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1725        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1726
1727        let mask = BooleanArray::from(vec![true, true]);
1728        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1729        let actual = out.as_string_view();
1730        let expected = StringViewArray::from(vec![
1731            Some("longer than 12 bytes"),
1732            Some("longer than 12 bytes"),
1733        ]);
1734        assert_eq!(actual, &expected);
1735    }
1736
1737    #[test]
1738    fn test_zip_kernel_scalar_strings_array_view_large_all_false() {
1739        let scalar_truthy = Scalar::new(StringViewArray::from(vec!["longer than 12 bytes"]));
1740        let scalar_falsy = Scalar::new(StringViewArray::from(vec!["another longer than 12 bytes"]));
1741
1742        let mask = BooleanArray::from(vec![false, false]);
1743        let out = zip(&mask, &scalar_truthy, &scalar_falsy).unwrap();
1744        let actual = out.as_string_view();
1745        let expected = StringViewArray::from(vec![
1746            Some("another longer than 12 bytes"),
1747            Some("another longer than 12 bytes"),
1748        ]);
1749        assert_eq!(actual, &expected);
1750    }
1751}