Skip to main content

arrow_array/builder/
generic_bytes_builder.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::builder::ArrayBuilder;
19use crate::types::{ByteArrayType, GenericBinaryType, GenericStringType};
20use crate::{Array, ArrayRef, GenericByteArray, OffsetSizeTrait};
21use arrow_buffer::{ArrowNativeType, Buffer, MutableBuffer, NullBufferBuilder, ScalarBuffer};
22use arrow_data::ArrayDataBuilder;
23use arrow_schema::ArrowError;
24use std::any::Any;
25use std::sync::Arc;
26
27/// Builder for [`GenericByteArray`]
28///
29/// For building strings, see docs on [`GenericStringBuilder`].
30/// For building binary, see docs on [`GenericBinaryBuilder`].
31pub struct GenericByteBuilder<T: ByteArrayType> {
32    value_builder: Vec<u8>,
33    offsets_builder: Vec<T::Offset>,
34    null_buffer_builder: NullBufferBuilder,
35}
36
37impl<T: ByteArrayType> GenericByteBuilder<T> {
38    /// Creates a new [`GenericByteBuilder`].
39    pub fn new() -> Self {
40        Self::with_capacity(1024, 1024)
41    }
42
43    /// Creates a new [`GenericByteBuilder`].
44    ///
45    /// - `item_capacity` is the number of items to pre-allocate.
46    ///   The size of the preallocated buffer of offsets is the number of items plus one.
47    /// - `data_capacity` is the total number of bytes of data to pre-allocate
48    ///   (for all items, not per item).
49    pub fn with_capacity(item_capacity: usize, data_capacity: usize) -> Self {
50        let mut offsets_builder = Vec::with_capacity(item_capacity + 1);
51        offsets_builder.push(T::Offset::from_usize(0).unwrap());
52        Self {
53            value_builder: Vec::with_capacity(data_capacity),
54            offsets_builder,
55            null_buffer_builder: NullBufferBuilder::new(item_capacity),
56        }
57    }
58
59    /// Creates a new  [`GenericByteBuilder`] from buffers.
60    ///
61    /// Any bytes in `value_buffer` after the last offset are dropped. The first
62    /// bit of `null_buffer` is for the first row.
63    ///
64    /// # Safety
65    ///
66    /// This doesn't verify buffer contents as it assumes the buffers are from
67    /// existing and valid [`GenericByteArray`].
68    pub unsafe fn new_from_buffer(
69        offsets_buffer: MutableBuffer,
70        mut value_buffer: MutableBuffer,
71        null_buffer: Option<MutableBuffer>,
72    ) -> Self {
73        let offsets_builder: Vec<T::Offset> =
74            ScalarBuffer::<T::Offset>::from(offsets_buffer).into();
75
76        // New values are appended at the end of the values buffer, so it must end
77        // at the last offset
78        value_buffer.truncate(offsets_builder.last().unwrap().as_usize());
79        let value_builder: Vec<u8> = ScalarBuffer::<u8>::from(value_buffer).into();
80
81        let null_buffer_builder = null_buffer
82            .map(|buffer| NullBufferBuilder::new_from_buffer(buffer, offsets_builder.len() - 1))
83            .unwrap_or_else(|| NullBufferBuilder::new_with_len(offsets_builder.len() - 1));
84
85        Self {
86            offsets_builder,
87            value_builder,
88            null_buffer_builder,
89        }
90    }
91
92    #[inline]
93    fn next_offset(&self) -> T::Offset {
94        T::Offset::from_usize(self.value_builder.len()).expect("byte array offset overflow")
95    }
96
97    /// Appends a value into the builder.
98    ///
99    /// See the [GenericStringBuilder] documentation for examples of
100    /// incrementally building string values with multiple `write!` calls.
101    ///
102    /// # Panics
103    ///
104    /// Panics if the resulting length of [`Self::values_slice`] would exceed
105    /// `T::Offset::MAX` bytes.
106    ///
107    /// For example, this can happen with [`StringArray`] or [`BinaryArray`]
108    /// where the total length of all values exceeds 2GB
109    ///
110    /// [`StringArray`]: crate::StringArray
111    /// [`BinaryArray`]: crate::BinaryArray
112    #[inline]
113    pub fn append_value(&mut self, value: impl AsRef<T::Native>) {
114        self.value_builder
115            .extend_from_slice(value.as_ref().as_ref());
116        self.null_buffer_builder.append(true);
117        self.offsets_builder.push(self.next_offset());
118    }
119
120    /// Appends a value of type `T` into the builder `n` times.
121    ///
122    /// See [`Self::append_value`] for more panic information.
123    #[inline]
124    pub fn append_value_n(&mut self, value: impl AsRef<T::Native>, n: usize) {
125        let bytes: &[u8] = value.as_ref().as_ref();
126        self.value_builder.reserve(bytes.len() * n);
127        self.offsets_builder.reserve(n);
128        for _ in 0..n {
129            self.value_builder.extend_from_slice(bytes);
130            self.offsets_builder.push(self.next_offset());
131        }
132        self.null_buffer_builder.append_n_non_nulls(n);
133    }
134
135    /// Append an `Option` value into the builder.
136    ///
137    /// - A `None` value will append a null value.
138    /// - A `Some` value will append the value.
139    ///
140    /// See [`Self::append_value`] for more panic information.
141    #[inline]
142    pub fn append_option(&mut self, value: Option<impl AsRef<T::Native>>) {
143        match value {
144            None => self.append_null(),
145            Some(v) => self.append_value(v),
146        };
147    }
148
149    /// Append a null value into the builder.
150    #[inline]
151    pub fn append_null(&mut self) {
152        self.null_buffer_builder.append(false);
153        self.offsets_builder.push(self.next_offset());
154    }
155
156    /// Appends `n` `null`s into the builder.
157    #[inline]
158    pub fn append_nulls(&mut self, n: usize) {
159        self.null_buffer_builder.append_n_nulls(n);
160        let next_offset = self.next_offset();
161        self.offsets_builder
162            .extend(std::iter::repeat_n(next_offset, n));
163    }
164
165    /// Appends array values and null to this builder as is
166    /// (this means that underlying null values are copied as is).
167    #[inline]
168    pub fn append_array(&mut self, array: &GenericByteArray<T>) -> Result<(), ArrowError> {
169        use num_traits::CheckedAdd;
170        if array.len() == 0 {
171            return Ok(());
172        }
173
174        let offsets = array.offsets();
175
176        // If the offsets are contiguous, we can append them directly avoiding the need to align
177        // for example, when the first appended array is not sliced (starts at offset 0)
178        if self.next_offset() == offsets[0] {
179            self.offsets_builder.extend_from_slice(&offsets[1..]);
180        } else {
181            // Shifting all the offsets
182            let shift: T::Offset = self.next_offset() - offsets[0];
183
184            if shift.checked_add(&offsets[offsets.len() - 1]).is_none() {
185                return Err(ArrowError::OffsetOverflowError(
186                    shift.as_usize() + offsets[offsets.len() - 1].as_usize(),
187                ));
188            }
189
190            self.offsets_builder
191                .extend(offsets[1..].iter().map(|&offset| offset + shift));
192        }
193
194        // Append underlying values, starting from the first offset and ending at the last offset
195        self.value_builder.extend_from_slice(
196            &array.values().as_slice()[offsets[0].as_usize()..offsets[array.len()].as_usize()],
197        );
198
199        if let Some(null_buffer) = array.nulls() {
200            self.null_buffer_builder.append_buffer(null_buffer);
201        } else {
202            self.null_buffer_builder.append_n_non_nulls(array.len());
203        }
204        Ok(())
205    }
206
207    /// Builds the [`GenericByteArray`] and reset this builder.
208    pub fn finish(&mut self) -> GenericByteArray<T> {
209        let array_type = T::DATA_TYPE;
210        let array_builder = ArrayDataBuilder::new(array_type)
211            .len(self.len())
212            .add_buffer(std::mem::take(&mut self.offsets_builder).into())
213            .add_buffer(std::mem::take(&mut self.value_builder).into())
214            .nulls(self.null_buffer_builder.finish());
215
216        self.offsets_builder.push(self.next_offset());
217        let array_data = unsafe { array_builder.build_unchecked() };
218        GenericByteArray::from(array_data)
219    }
220
221    /// Builds the [`GenericByteArray`] without resetting the builder.
222    pub fn finish_cloned(&self) -> GenericByteArray<T> {
223        let array_type = T::DATA_TYPE;
224        let offset_buffer = Buffer::from_slice_ref(self.offsets_builder.as_slice());
225        let value_buffer = Buffer::from_slice_ref(self.value_builder.as_slice());
226        let array_builder = ArrayDataBuilder::new(array_type)
227            .len(self.len())
228            .add_buffer(offset_buffer)
229            .add_buffer(value_buffer)
230            .nulls(self.null_buffer_builder.finish_cloned());
231
232        let array_data = unsafe { array_builder.build_unchecked() };
233        GenericByteArray::from(array_data)
234    }
235
236    /// Returns the current values buffer as a slice
237    pub fn values_slice(&self) -> &[u8] {
238        self.value_builder.as_slice()
239    }
240
241    /// Returns the current values buffer capacity, in bytes.
242    pub fn values_capacity(&self) -> usize {
243        self.value_builder.capacity()
244    }
245
246    /// Returns the current offsets buffer as a slice
247    pub fn offsets_slice(&self) -> &[T::Offset] {
248        self.offsets_builder.as_slice()
249    }
250
251    /// Returns the current offsets buffer capacity, in offsets.
252    pub fn offsets_capacity(&self) -> usize {
253        self.offsets_builder.capacity()
254    }
255
256    /// Returns the current null buffer as a slice
257    pub fn validity_slice(&self) -> Option<&[u8]> {
258        self.null_buffer_builder.as_slice()
259    }
260
261    /// Returns the current null buffer allocated capacity, in bytes.
262    pub fn validity_capacity(&self) -> usize {
263        self.null_buffer_builder.allocated_size()
264    }
265
266    /// Returns the current null buffer as a mutable slice
267    pub fn validity_slice_mut(&mut self) -> Option<&mut [u8]> {
268        self.null_buffer_builder.as_slice_mut()
269    }
270}
271
272impl<T: ByteArrayType> std::fmt::Debug for GenericByteBuilder<T> {
273    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
274        write!(f, "{}{}Builder", T::Offset::PREFIX, T::PREFIX)?;
275        f.debug_struct("")
276            .field("value_builder", &self.value_builder)
277            .field("offsets_builder", &self.offsets_builder)
278            .field("null_buffer_builder", &self.null_buffer_builder)
279            .finish()
280    }
281}
282
283impl<T: ByteArrayType> Default for GenericByteBuilder<T> {
284    fn default() -> Self {
285        Self::new()
286    }
287}
288
289impl<T: ByteArrayType> ArrayBuilder for GenericByteBuilder<T> {
290    /// Returns the number of binary slots in the builder
291    fn len(&self) -> usize {
292        self.null_buffer_builder.len()
293    }
294
295    /// Builds the array and reset this builder.
296    fn finish(&mut self) -> ArrayRef {
297        Arc::new(self.finish())
298    }
299
300    /// Builds the array without resetting the builder.
301    fn finish_cloned(&self) -> ArrayRef {
302        Arc::new(self.finish_cloned())
303    }
304
305    /// Returns the builder as a non-mutable `Any` reference.
306    fn as_any(&self) -> &dyn Any {
307        self
308    }
309
310    /// Returns the builder as a mutable `Any` reference.
311    fn as_any_mut(&mut self) -> &mut dyn Any {
312        self
313    }
314
315    /// Returns the boxed builder as a box of `Any`.
316    fn into_box_any(self: Box<Self>) -> Box<dyn Any> {
317        self
318    }
319}
320
321impl<T: ByteArrayType, V: AsRef<T::Native>> Extend<Option<V>> for GenericByteBuilder<T> {
322    #[inline]
323    fn extend<I: IntoIterator<Item = Option<V>>>(&mut self, iter: I) {
324        for v in iter {
325            self.append_option(v)
326        }
327    }
328}
329
330/// Array builder for [`GenericStringArray`][crate::GenericStringArray]
331///
332/// Values can be appended using [`GenericByteBuilder::append_value`], and nulls with
333/// [`GenericByteBuilder::append_null`].
334///
335/// This builder also implements [`std::fmt::Write`] with any written data
336/// included in the next appended value. This allows using [`std::fmt::Display`]
337/// with standard Rust idioms like `write!` and `writeln!` to write data
338/// directly to the builder without intermediate allocations.
339///
340/// # Example writing strings with `append_value`
341/// ```
342/// # use arrow_array::builder::GenericStringBuilder;
343/// let mut builder = GenericStringBuilder::<i32>::new();
344///
345/// // Write one string value
346/// builder.append_value("foobarbaz");
347///
348/// // Write a second string
349/// builder.append_value("v2");
350///
351/// let array = builder.finish();
352/// assert_eq!(array.value(0), "foobarbaz");
353/// assert_eq!(array.value(1), "v2");
354/// ```
355///
356/// # Example incrementally writing strings with `std::fmt::Write`
357///
358/// ```
359/// # use std::fmt::Write;
360/// # use arrow_array::builder::GenericStringBuilder;
361/// let mut builder = GenericStringBuilder::<i32>::new();
362///
363/// // Write data in multiple `write!` calls
364/// write!(builder, "foo").unwrap();
365/// write!(builder, "bar").unwrap();
366/// // The next call to append_value finishes the current string
367/// // including all previously written strings.
368/// builder.append_value("baz");
369///
370/// // Write second value with a single write call
371/// write!(builder, "v2").unwrap();
372/// // finish the value by calling append_value with an empty string
373/// builder.append_value("");
374///
375/// let array = builder.finish();
376/// assert_eq!(array.value(0), "foobarbaz");
377/// assert_eq!(array.value(1), "v2");
378/// ```
379pub type GenericStringBuilder<O> = GenericByteBuilder<GenericStringType<O>>;
380
381impl<O: OffsetSizeTrait> std::fmt::Write for GenericStringBuilder<O> {
382    fn write_str(&mut self, s: &str) -> std::fmt::Result {
383        self.value_builder.extend_from_slice(s.as_bytes());
384        Ok(())
385    }
386}
387
388/// A byte size value representing the number of bytes to allocate per string in [`GenericStringBuilder`]
389///
390/// To create a [`GenericStringBuilder`] using `.with_capacity` we are required to provide: \
391/// - `item_capacity` - the row count \
392/// - `data_capacity` - total string byte count \
393///
394/// We will use the `AVERAGE_STRING_LENGTH` * row_count for `data_capacity`. \
395///
396/// These capacities are preallocation hints used to improve performance,
397/// but consequences of passing a hint too large or too small should be negligible.
398const AVERAGE_STRING_LENGTH: usize = 16;
399/// Trait for string-like array builders
400///
401/// This trait provides unified interface for builders that append string-like data
402/// such as [`GenericStringBuilder<O>`] and [`crate::builder::StringViewBuilder`]
403pub trait StringLikeArrayBuilder: ArrayBuilder {
404    /// Returns a human-readable type name for the builder.
405    fn type_name() -> &'static str;
406
407    /// Creates a new builder with the given row capacity.
408    fn with_capacity(capacity: usize) -> Self;
409
410    /// Appends a non-null string value to the builder.
411    fn append_value(&mut self, value: &str);
412
413    /// Appends a null value to the builder.
414    fn append_null(&mut self);
415}
416
417impl<O: OffsetSizeTrait> StringLikeArrayBuilder for GenericStringBuilder<O> {
418    fn type_name() -> &'static str {
419        std::any::type_name::<Self>()
420    }
421    fn with_capacity(capacity: usize) -> Self {
422        Self::with_capacity(capacity, capacity * AVERAGE_STRING_LENGTH)
423    }
424    fn append_value(&mut self, value: &str) {
425        Self::append_value(self, value);
426    }
427    fn append_null(&mut self) {
428        Self::append_null(self);
429    }
430}
431
432/// A byte size value representing the number of bytes to allocate per binary in [`GenericBinaryBuilder`]
433///
434/// To create a [`GenericBinaryBuilder`] using `.with_capacity` we are required to provide: \
435/// - `item_capacity` - the row count \
436/// - `data_capacity` - total binary byte count \
437///
438/// We will use the `AVERAGE_BINARY_LENGTH` * row_count for `data_capacity`. \
439///
440/// These capacities are preallocation hints used to improve performance,
441/// but consequences of passing a hint too large or too small should be negligible.
442const AVERAGE_BINARY_LENGTH: usize = 128;
443/// Trait for binary-like array builders
444///
445/// This trait provides unified interface for builders that append binary-like data
446/// such as [`GenericBinaryBuilder<O>`] and [`crate::builder::BinaryViewBuilder`]
447pub trait BinaryLikeArrayBuilder: ArrayBuilder {
448    /// Returns a human-readable type name for the builder.
449    fn type_name() -> &'static str;
450
451    /// Creates a new builder with the given row capacity.
452    fn with_capacity(capacity: usize) -> Self;
453
454    /// Appends a non-null string value to the builder.
455    fn append_value(&mut self, value: &[u8]);
456
457    /// Appends a null value to the builder.
458    fn append_null(&mut self);
459}
460
461impl<O: OffsetSizeTrait> BinaryLikeArrayBuilder for GenericBinaryBuilder<O> {
462    fn type_name() -> &'static str {
463        std::any::type_name::<Self>()
464    }
465    fn with_capacity(capacity: usize) -> Self {
466        Self::with_capacity(capacity, capacity * AVERAGE_BINARY_LENGTH)
467    }
468    fn append_value(&mut self, value: &[u8]) {
469        Self::append_value(self, value);
470    }
471    fn append_null(&mut self) {
472        Self::append_null(self);
473    }
474}
475
476///  Array builder for [`GenericBinaryArray`][crate::GenericBinaryArray]
477///
478/// Values can be appended using [`GenericByteBuilder::append_value`], and nulls with
479/// [`GenericByteBuilder::append_null`].
480///
481/// # Example
482/// ```
483/// # use arrow_array::builder::GenericBinaryBuilder;
484/// let mut builder = GenericBinaryBuilder::<i32>::new();
485///
486/// // Write data
487/// builder.append_value("foo");
488///
489/// // Write second value
490/// builder.append_value(&[0,1,2]);
491///
492/// let array = builder.finish();
493/// // binary values
494/// assert_eq!(array.value(0), b"foo");
495/// assert_eq!(array.value(1), b"\x00\x01\x02");
496/// ```
497///
498/// # Example incrementally writing bytes with `write_bytes`
499///
500/// ```
501/// # use std::io::Write;
502/// # use arrow_array::builder::GenericBinaryBuilder;
503/// let mut builder = GenericBinaryBuilder::<i32>::new();
504///
505/// // Write data in multiple `write_bytes` calls
506/// write!(builder, "foo").unwrap();
507/// write!(builder, "bar").unwrap();
508/// // The next call to append_value finishes the current string
509/// // including all previously written strings.
510/// builder.append_value("baz");
511///
512/// // Write second value with a single write call
513/// write!(builder, "v2").unwrap();
514/// // finish the value by calling append_value with an empty string
515/// builder.append_value("");
516///
517/// let array = builder.finish();
518/// assert_eq!(array.value(0), "foobarbaz".as_bytes());
519/// assert_eq!(array.value(1), "v2".as_bytes());
520/// ```
521pub type GenericBinaryBuilder<O> = GenericByteBuilder<GenericBinaryType<O>>;
522
523impl<O: OffsetSizeTrait> std::io::Write for GenericBinaryBuilder<O> {
524    fn write(&mut self, bs: &[u8]) -> std::io::Result<usize> {
525        self.value_builder.extend_from_slice(bs);
526        Ok(bs.len())
527    }
528
529    fn flush(&mut self) -> std::io::Result<()> {
530        Ok(())
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537    use crate::GenericStringArray;
538    use crate::array::Array;
539    use arrow_buffer::NullBuffer;
540    use std::fmt::Write as _;
541    use std::io::Write as _;
542
543    fn _test_generic_binary_builder<O: OffsetSizeTrait>() {
544        let mut builder = GenericBinaryBuilder::<O>::new();
545
546        builder.append_value(b"hello");
547        builder.append_value(b"");
548        builder.append_null();
549        builder.append_value(b"rust");
550
551        let array = builder.finish();
552
553        assert_eq!(4, array.len());
554        assert_eq!(1, array.null_count());
555        assert_eq!(b"hello", array.value(0));
556        assert_eq!([] as [u8; 0], array.value(1));
557        assert!(array.is_null(2));
558        assert_eq!(b"rust", array.value(3));
559        assert_eq!(O::from_usize(5).unwrap(), array.value_offsets()[2]);
560        assert_eq!(O::from_usize(4).unwrap(), array.value_length(3));
561    }
562
563    #[test]
564    fn test_binary_builder() {
565        _test_generic_binary_builder::<i32>()
566    }
567
568    #[test]
569    fn test_large_binary_builder() {
570        _test_generic_binary_builder::<i64>()
571    }
572
573    fn _test_generic_binary_builder_all_nulls<O: OffsetSizeTrait>() {
574        let mut builder = GenericBinaryBuilder::<O>::new();
575        builder.append_null();
576        builder.append_null();
577        builder.append_null();
578        builder.append_nulls(2);
579        assert_eq!(5, builder.len());
580        assert!(!builder.is_empty());
581
582        let array = builder.finish();
583        assert_eq!(5, array.null_count());
584        assert_eq!(5, array.len());
585        assert!(array.is_null(0));
586        assert!(array.is_null(1));
587        assert!(array.is_null(2));
588        assert!(array.is_null(3));
589        assert!(array.is_null(4));
590    }
591
592    #[test]
593    fn test_binary_builder_all_nulls() {
594        _test_generic_binary_builder_all_nulls::<i32>()
595    }
596
597    #[test]
598    fn test_large_binary_builder_all_nulls() {
599        _test_generic_binary_builder_all_nulls::<i64>()
600    }
601
602    fn _test_generic_binary_builder_reset<O: OffsetSizeTrait>() {
603        let mut builder = GenericBinaryBuilder::<O>::new();
604
605        builder.append_value(b"hello");
606        builder.append_value(b"");
607        builder.append_null();
608        builder.append_value(b"rust");
609        builder.finish();
610
611        assert!(builder.is_empty());
612
613        builder.append_value(b"parquet");
614        builder.append_null();
615        builder.append_value(b"arrow");
616        builder.append_value(b"");
617        builder.append_nulls(2);
618        builder.append_value(b"hi");
619        let array = builder.finish();
620
621        assert_eq!(7, array.len());
622        assert_eq!(3, array.null_count());
623        assert_eq!(b"parquet", array.value(0));
624        assert!(array.is_null(1));
625        assert!(array.is_null(4));
626        assert!(array.is_null(5));
627        assert_eq!(b"arrow", array.value(2));
628        assert_eq!(b"", array.value(1));
629        assert_eq!(b"hi", array.value(6));
630
631        assert_eq!(O::zero(), array.value_offsets()[0]);
632        assert_eq!(O::from_usize(7).unwrap(), array.value_offsets()[2]);
633        assert_eq!(O::from_usize(14).unwrap(), array.value_offsets()[7]);
634        assert_eq!(O::from_usize(5).unwrap(), array.value_length(2));
635    }
636
637    #[test]
638    fn test_binary_builder_reset() {
639        _test_generic_binary_builder_reset::<i32>()
640    }
641
642    #[test]
643    fn test_large_binary_builder_reset() {
644        _test_generic_binary_builder_reset::<i64>()
645    }
646
647    fn _test_generic_string_array_builder<O: OffsetSizeTrait>() {
648        let mut builder = GenericStringBuilder::<O>::new();
649        let owned = "arrow".to_owned();
650
651        builder.append_value("hello");
652        builder.append_value("");
653        builder.append_value(&owned);
654        builder.append_null();
655        builder.append_option(Some("rust"));
656        builder.append_option(None::<&str>);
657        builder.append_option(None::<String>);
658        builder.append_nulls(2);
659        builder.append_value("parquet");
660        assert_eq!(10, builder.len());
661
662        assert_eq!(
663            GenericStringArray::<O>::from(vec![
664                Some("hello"),
665                Some(""),
666                Some("arrow"),
667                None,
668                Some("rust"),
669                None,
670                None,
671                None,
672                None,
673                Some("parquet")
674            ]),
675            builder.finish()
676        );
677    }
678
679    #[test]
680    fn test_string_array_builder() {
681        _test_generic_string_array_builder::<i32>()
682    }
683
684    #[test]
685    fn test_large_string_array_builder() {
686        _test_generic_string_array_builder::<i64>()
687    }
688
689    fn _test_generic_string_array_builder_finish<O: OffsetSizeTrait>() {
690        let mut builder = GenericStringBuilder::<O>::with_capacity(3, 11);
691
692        builder.append_value("hello");
693        builder.append_value("rust");
694        builder.append_null();
695
696        builder.finish();
697        assert!(builder.is_empty());
698        assert_eq!(&[O::zero()], builder.offsets_slice());
699
700        builder.append_value("arrow");
701        builder.append_value("parquet");
702        let arr = builder.finish();
703        // array should not have null buffer because there is not `null` value.
704        assert!(arr.nulls().is_none());
705        assert_eq!(GenericStringArray::<O>::from(vec!["arrow", "parquet"]), arr,)
706    }
707
708    #[test]
709    fn test_string_array_builder_finish() {
710        _test_generic_string_array_builder_finish::<i32>()
711    }
712
713    #[test]
714    fn test_large_string_array_builder_finish() {
715        _test_generic_string_array_builder_finish::<i64>()
716    }
717
718    fn _test_generic_string_array_builder_finish_cloned<O: OffsetSizeTrait>() {
719        let mut builder = GenericStringBuilder::<O>::with_capacity(3, 11);
720
721        builder.append_value("hello");
722        builder.append_value("rust");
723        builder.append_null();
724
725        let mut arr = builder.finish_cloned();
726        assert!(!builder.is_empty());
727        assert_eq!(3, arr.len());
728
729        builder.append_value("arrow");
730        builder.append_value("parquet");
731        arr = builder.finish();
732
733        assert!(arr.nulls().is_some());
734        assert_eq!(&[O::zero()], builder.offsets_slice());
735        assert_eq!(5, arr.len());
736    }
737
738    #[test]
739    fn test_string_array_builder_finish_cloned() {
740        _test_generic_string_array_builder_finish_cloned::<i32>()
741    }
742
743    #[test]
744    fn test_large_string_array_builder_finish_cloned() {
745        _test_generic_string_array_builder_finish_cloned::<i64>()
746    }
747
748    #[test]
749    fn test_extend() {
750        let mut builder = GenericStringBuilder::<i32>::new();
751        builder.extend(["a", "b", "c", "", "a", "b", "c"].into_iter().map(Some));
752        builder.extend(["d", "cupcakes", "hello"].into_iter().map(Some));
753        let array = builder.finish();
754        assert_eq!(array.value_offsets(), &[0, 1, 2, 3, 3, 4, 5, 6, 7, 15, 20]);
755        assert_eq!(array.value_data(), b"abcabcdcupcakeshello");
756    }
757
758    #[test]
759    fn test_write_str() {
760        let mut builder = GenericStringBuilder::<i32>::new();
761        write!(builder, "foo").unwrap();
762        builder.append_value("");
763        writeln!(builder, "bar").unwrap();
764        builder.append_value("");
765        write!(builder, "fiz").unwrap();
766        write!(builder, "buz").unwrap();
767        builder.append_value("");
768        let a = builder.finish();
769        let r: Vec<_> = a.iter().flatten().collect();
770        assert_eq!(r, &["foo", "bar\n", "fizbuz"])
771    }
772
773    #[test]
774    fn test_write_bytes() {
775        let mut builder = GenericBinaryBuilder::<i32>::new();
776        write!(builder, "foo").unwrap();
777        builder.append_value("");
778        writeln!(builder, "bar").unwrap();
779        builder.append_value("");
780        write!(builder, "fiz").unwrap();
781        write!(builder, "buz").unwrap();
782        builder.append_value("");
783        let a = builder.finish();
784        let r: Vec<_> = a.iter().flatten().collect();
785        assert_eq!(
786            r,
787            &["foo".as_bytes(), "bar\n".as_bytes(), "fizbuz".as_bytes()]
788        )
789    }
790
791    #[test]
792    fn test_append_array_without_nulls() {
793        let input = vec![
794            "hello", "world", "how", "are", "you", "doing", "today", "I", "am", "doing", "well",
795            "thank", "you", "for", "asking",
796        ];
797        let arr1 = GenericStringArray::<i32>::from(input[..3].to_vec());
798        let arr2 = GenericStringArray::<i32>::from(input[3..7].to_vec());
799        let arr3 = GenericStringArray::<i32>::from(input[7..].to_vec());
800
801        let mut builder = GenericStringBuilder::<i32>::new();
802        builder.append_array(&arr1).unwrap();
803        builder.append_array(&arr2).unwrap();
804        builder.append_array(&arr3).unwrap();
805
806        let actual = builder.finish();
807        let expected = GenericStringArray::<i32>::from(input);
808
809        assert_eq!(actual, expected);
810    }
811
812    #[test]
813    fn test_append_array_with_nulls() {
814        let input = vec![
815            Some("hello"),
816            None,
817            Some("how"),
818            None,
819            None,
820            None,
821            None,
822            Some("I"),
823            Some("am"),
824            Some("doing"),
825            Some("well"),
826        ];
827        let arr1 = GenericStringArray::<i32>::from(input[..3].to_vec());
828        let arr2 = GenericStringArray::<i32>::from(input[3..7].to_vec());
829        let arr3 = GenericStringArray::<i32>::from(input[7..].to_vec());
830
831        let mut builder = GenericStringBuilder::<i32>::new();
832        builder.append_array(&arr1).unwrap();
833        builder.append_array(&arr2).unwrap();
834        builder.append_array(&arr3).unwrap();
835
836        let actual = builder.finish();
837        let expected = GenericStringArray::<i32>::from(input);
838
839        assert_eq!(actual, expected);
840    }
841
842    #[test]
843    fn test_append_empty_array() {
844        let arr = GenericStringArray::<i32>::from(Vec::<&str>::new());
845        let mut builder = GenericStringBuilder::<i32>::new();
846        builder.append_array(&arr).unwrap();
847        let result = builder.finish();
848        assert_eq!(result.len(), 0);
849    }
850
851    #[test]
852    fn test_append_array_with_offset_not_starting_at_0() {
853        let input = vec![
854            Some("hello"),
855            None,
856            Some("how"),
857            None,
858            None,
859            None,
860            None,
861            Some("I"),
862            Some("am"),
863            Some("doing"),
864            Some("well"),
865        ];
866        let full_array = GenericStringArray::<i32>::from(input);
867        let sliced = full_array.slice(1, 4);
868
869        assert_ne!(sliced.offsets()[0].as_usize(), 0);
870        assert_ne!(sliced.offsets().last(), full_array.offsets().last());
871
872        let mut builder = GenericStringBuilder::<i32>::new();
873        builder.append_array(&sliced).unwrap();
874        let actual = builder.finish();
875
876        let expected = GenericStringArray::<i32>::from(vec![None, Some("how"), None, None]);
877
878        assert_eq!(actual, expected);
879    }
880
881    #[test]
882    fn test_append_underlying_null_values_added_as_is() {
883        let input_1_array_with_nulls = {
884            let input = vec![
885                "hello", "world", "how", "are", "you", "doing", "today", "I", "am",
886            ];
887            let (offsets, buffer, _) = GenericStringArray::<i32>::from(input).into_parts();
888
889            GenericStringArray::<i32>::new(
890                offsets,
891                buffer,
892                Some(NullBuffer::from(&[
893                    true, false, true, false, false, true, true, true, false,
894                ])),
895            )
896        };
897        let input_2_array_with_nulls = {
898            let input = vec!["doing", "well", "thank", "you", "for", "asking"];
899            let (offsets, buffer, _) = GenericStringArray::<i32>::from(input).into_parts();
900
901            GenericStringArray::<i32>::new(
902                offsets,
903                buffer,
904                Some(NullBuffer::from(&[false, false, true, false, true, true])),
905            )
906        };
907
908        let mut builder = GenericStringBuilder::<i32>::new();
909        builder.append_array(&input_1_array_with_nulls).unwrap();
910        builder.append_array(&input_2_array_with_nulls).unwrap();
911
912        let actual = builder.finish();
913        let expected = GenericStringArray::<i32>::from(vec![
914            Some("hello"),
915            None, // world
916            Some("how"),
917            None, // are
918            None, // you
919            Some("doing"),
920            Some("today"),
921            Some("I"),
922            None, // am
923            None, // doing
924            None, // well
925            Some("thank"),
926            None, // "you",
927            Some("for"),
928            Some("asking"),
929        ]);
930
931        assert_eq!(actual, expected);
932
933        let expected_underlying_buffer = Buffer::from(
934            [
935                "hello", "world", "how", "are", "you", "doing", "today", "I", "am", "doing",
936                "well", "thank", "you", "for", "asking",
937            ]
938            .join("")
939            .as_bytes(),
940        );
941        assert_eq!(actual.values(), &expected_underlying_buffer);
942    }
943
944    #[test]
945    fn append_array_with_continues_indices() {
946        let input = vec![
947            "hello", "world", "how", "are", "you", "doing", "today", "I", "am", "doing", "well",
948            "thank", "you", "for", "asking",
949        ];
950        let full_array = GenericStringArray::<i32>::from(input);
951        let slice1 = full_array.slice(0, 3);
952        let slice2 = full_array.slice(3, 4);
953        let slice3 = full_array.slice(7, full_array.len() - 7);
954
955        let mut builder = GenericStringBuilder::<i32>::new();
956        builder.append_array(&slice1).unwrap();
957        builder.append_array(&slice2).unwrap();
958        builder.append_array(&slice3).unwrap();
959
960        let actual = builder.finish();
961
962        assert_eq!(actual, full_array);
963    }
964
965    #[test]
966    fn test_append_array_offset_overflow_precise() {
967        let mut builder = GenericStringBuilder::<i32>::new();
968
969        let initial_string = "x".repeat(i32::MAX as usize - 100);
970        builder.append_value(&initial_string);
971
972        let overflow_string = "y".repeat(200);
973        let overflow_array = GenericStringArray::<i32>::from(vec![overflow_string.as_str()]);
974
975        let result = builder.append_array(&overflow_array);
976
977        assert!(matches!(result, Err(ArrowError::OffsetOverflowError(_))));
978    }
979
980    #[test]
981    fn test_append_value_n() {
982        let mut builder = GenericStringBuilder::<i32>::new();
983        builder.append_value("hello");
984        builder.append_value_n("world", 3);
985        builder.append_null();
986        let array = builder.finish();
987
988        assert_eq!(5, array.len());
989        assert_eq!(1, array.null_count());
990        assert_eq!("hello", array.value(0));
991        assert_eq!("world", array.value(1));
992        assert_eq!("world", array.value(2));
993        assert_eq!("world", array.value(3));
994        assert!(array.is_null(4));
995    }
996}