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