Skip to main content

arrow_array/
ffi.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//! Contains declarations to bind to the [C Data Interface](https://arrow.apache.org/docs/format/CDataInterface.html).
19//!
20//! Generally, this module is divided in two main interfaces:
21//! One interface maps C ABI to native Rust types, i.e. convert c-pointers, c_char, to native rust.
22//! This is handled by [FFI_ArrowSchema] and [FFI_ArrowArray].
23//!
24//! The second interface maps native Rust types to the Rust-specific implementation of Arrow such as `format` to `Datatype`,
25//! `Buffer`, etc. This is handled by `from_ffi` and `to_ffi`.
26//!
27//!
28//! Export to FFI
29//!
30//! ```rust
31//! # use std::sync::Arc;
32//! # use arrow_array::{Int32Array, Array, make_array};
33//! # use arrow_data::ArrayData;
34//! # use arrow_array::ffi::{to_ffi, from_ffi};
35//! # use arrow_schema::ArrowError;
36//! # fn main() -> Result<(), ArrowError> {
37//! // create an array natively
38//!
39//! let array = Int32Array::from(vec![Some(1), None, Some(3)]);
40//! let data = array.into_data();
41//!
42//! // Export it
43//! let (out_array, out_schema) = to_ffi(&data)?;
44//!
45//! // import it
46//! let data = unsafe { from_ffi(out_array, &out_schema) }?;
47//! let array = Int32Array::from(data);
48//!
49//! // verify
50//! assert_eq!(array, Int32Array::from(vec![Some(1), None, Some(3)]));
51//! #
52//! # Ok(())
53//! # }
54//! ```
55//!
56//! Import from FFI
57//!
58//! ```
59//! # use std::ptr::addr_of_mut;
60//! # use arrow_array::ffi::{from_ffi, FFI_ArrowArray};
61//! # use arrow_array::{ArrayRef, make_array};
62//! # use arrow_schema::{ArrowError, ffi::FFI_ArrowSchema};
63//! #
64//! /// A foreign data container that can export to C Data interface
65//! struct ForeignArray {};
66//!
67//! impl ForeignArray {
68//!     /// Export from foreign array representation to C Data interface
69//!     /// e.g. <https://github.com/apache/arrow/blob/fc1f9ebbc4c3ae77d5cfc2f9322f4373d3d19b8a/python/pyarrow/array.pxi#L1552>
70//!     fn export_to_c(&self, array: *mut FFI_ArrowArray, schema: *mut FFI_ArrowSchema) {
71//!         // ...
72//!     }
73//! }
74//!
75//! /// Import an [`ArrayRef`] from a [`ForeignArray`]
76//! fn import_array(foreign: &ForeignArray) -> Result<ArrayRef, ArrowError> {
77//!     let mut schema = FFI_ArrowSchema::empty();
78//!     let mut array = FFI_ArrowArray::empty();
79//!     foreign.export_to_c(addr_of_mut!(array), addr_of_mut!(schema));
80//!     Ok(make_array(unsafe { from_ffi(array, &schema) }?))
81//! }
82//! ```
83
84/*
85# Design:
86
87Main assumptions:
88* A memory region is deallocated according it its own release mechanism.
89* Rust shares memory regions between arrays.
90* A memory region should be deallocated when no-one is using it.
91
92The design of this module is as follows:
93
94`ArrowArray` contains two `Arc`s, one per ABI-compatible `struct`, each containing data
95according to the C Data Interface. These Arcs are used for ref counting of the structs
96within Rust and lifetime management.
97
98Each ABI-compatible `struct` knowns how to `drop` itself, calling `release`.
99
100To import an array, unsafely create an `ArrowArray` from two pointers using [ArrowArray::try_from_raw].
101To export an array, create an `ArrowArray` using [ArrowArray::try_new].
102*/
103
104use std::{mem::size_of, ptr::NonNull, sync::Arc};
105
106use arrow_buffer::{Buffer, MutableBuffer, bit_util};
107pub use arrow_data::ffi::FFI_ArrowArray;
108use arrow_data::{ArrayData, layout};
109pub use arrow_schema::ffi::FFI_ArrowSchema;
110use arrow_schema::{ArrowError, DataType, UnionMode};
111
112type Result<T> = std::result::Result<T, ArrowError>;
113
114/// returns the number of bits that buffer `i` (in the C data interface) is expected to have.
115/// This is set by the Arrow specification
116fn bit_width(data_type: &DataType, i: usize) -> Result<usize> {
117    if let Some(primitive) = data_type.primitive_width() {
118        return match i {
119            0 => Err(ArrowError::CDataInterface(format!(
120                "The datatype \"{data_type}\" doesn't expect buffer at index 0. Please verify that the C data interface is correctly implemented."
121            ))),
122            1 => Ok(primitive * 8),
123            i => Err(ArrowError::CDataInterface(format!(
124                "The datatype \"{data_type}\" expects 2 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
125            ))),
126        };
127    }
128
129    Ok(match (data_type, i) {
130        (DataType::Boolean, 1) => 1,
131        (DataType::Boolean, _) => {
132            return Err(ArrowError::CDataInterface(format!(
133                "The datatype \"{data_type}\" expects 2 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
134            )));
135        }
136        (DataType::FixedSizeBinary(num_bytes), 1) => {
137            TryInto::<usize>::try_into(*num_bytes).map_err(|_| {
138                ArrowError::InvalidArgumentError(format!(
139                    "cannot determine bit_width for FixedSizeBinary({num_bytes})"
140                ))
141            })? * u8::BITS as usize
142        }
143        (DataType::FixedSizeList(f, num_elems), 1) => {
144            let child_bit_width = bit_width(f.data_type(), 1)?;
145            child_bit_width * (*num_elems as usize)
146        }
147        (DataType::FixedSizeBinary(_) | DataType::FixedSizeList(_, _), _) => {
148            return Err(ArrowError::CDataInterface(format!(
149                "The datatype \"{data_type}\" expects 2 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
150            )));
151        }
152        // Variable-size list and map have one i32 buffer.
153        // Variable-sized binaries: have two buffers.
154        // "small": first buffer is i32, second is in bytes
155        (DataType::Utf8 | DataType::Binary | DataType::List(_) | DataType::Map(_, _), 1) => {
156            i32::BITS as _
157        }
158        (DataType::Utf8 | DataType::Binary, 2) => u8::BITS as _,
159        // List views have two i32 buffers, offsets and sizes
160        (DataType::ListView(_), 1 | 2) => i32::BITS as _,
161        // Large list views have two i64 buffers, offsets and sizes
162        (DataType::LargeListView(_), 1 | 2) => i64::BITS as _,
163        (DataType::List(_) | DataType::Map(_, _), _) => {
164            return Err(ArrowError::CDataInterface(format!(
165                "The datatype \"{data_type}\" expects 2 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
166            )));
167        }
168        (DataType::Utf8 | DataType::Binary, _) => {
169            return Err(ArrowError::CDataInterface(format!(
170                "The datatype \"{data_type}\" expects 3 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
171            )));
172        }
173        // Variable-sized binaries: have two buffers.
174        // LargeUtf8: first buffer is i64, second is in bytes
175        (DataType::LargeUtf8 | DataType::LargeBinary | DataType::LargeList(_), 1) => i64::BITS as _,
176        (DataType::LargeUtf8 | DataType::LargeBinary | DataType::LargeList(_), 2) => u8::BITS as _,
177        (DataType::LargeUtf8 | DataType::LargeBinary | DataType::LargeList(_), _) => {
178            return Err(ArrowError::CDataInterface(format!(
179                "The datatype \"{data_type}\" expects 3 buffers, but requested {i}. Please verify that the C data interface is correctly implemented."
180            )));
181        }
182        // Variable-sized views: have 3 or more buffers.
183        // Buffer 1 are the u128 views
184        // Buffers 2...N-1 are u8 byte buffers
185        (DataType::Utf8View | DataType::BinaryView, 1) => u128::BITS as _,
186        (DataType::Utf8View | DataType::BinaryView, _) => u8::BITS as _,
187        // type ids. UnionArray doesn't have null bitmap so buffer index begins with 0.
188        (DataType::Union(_, _), 0) => i8::BITS as _,
189        // Only DenseUnion has 2nd buffer
190        (DataType::Union(_, UnionMode::Dense), 1) => i32::BITS as _,
191        (DataType::Union(_, UnionMode::Sparse), _) => {
192            return Err(ArrowError::CDataInterface(format!(
193                "The datatype \"{data_type}\" expects 1 buffer, but requested {i}. Please verify that the C data interface is correctly implemented."
194            )));
195        }
196        (DataType::Union(_, UnionMode::Dense), _) => {
197            return Err(ArrowError::CDataInterface(format!(
198                "The datatype \"{data_type}\" expects 2 buffer, but requested {i}. Please verify that the C data interface is correctly implemented."
199            )));
200        }
201        (_, 0) => {
202            // We don't call this `bit_width` to compute buffer length for null buffer. If any types that don't have null buffer like
203            // UnionArray, they should be handled above.
204            return Err(ArrowError::CDataInterface(format!(
205                "The datatype \"{data_type}\" doesn't expect buffer at index 0. Please verify that the C data interface is correctly implemented."
206            )));
207        }
208        _ => {
209            return Err(ArrowError::CDataInterface(format!(
210                "The datatype \"{data_type}\" is still not supported in Rust implementation"
211            )));
212        }
213    })
214}
215
216/// returns a new buffer corresponding to the index `i` of the FFI array. It may not exist (null pointer).
217/// `bits` is the number of bits that the native type of this buffer has.
218/// The size of the buffer will be `ceil(self.length * bits, 8)`.
219/// # Panics
220/// This function panics if `i` is larger or equal to `n_buffers`.
221/// # Safety
222/// This function assumes that `ceil(self.length * bits, 8)` is the size of the buffer
223unsafe fn create_buffer(
224    owner: Arc<FFI_ArrowArray>,
225    array: &FFI_ArrowArray,
226    index: usize,
227    len: usize,
228) -> Option<Buffer> {
229    if array.num_buffers() == 0 {
230        return None;
231    }
232    NonNull::new(array.buffer(index).cast_mut())
233        .map(|ptr| unsafe { Buffer::from_custom_allocation(ptr, len, owner) })
234}
235
236/// Export to the C Data Interface
237pub fn to_ffi(data: &ArrayData) -> Result<(FFI_ArrowArray, FFI_ArrowSchema)> {
238    let array = FFI_ArrowArray::new(data);
239    let schema = FFI_ArrowSchema::try_from(data.data_type())?;
240    Ok((array, schema))
241}
242
243/// Import [ArrayData] from the C Data Interface
244///
245/// # Safety
246///
247/// This struct assumes that the incoming data agrees with the C data interface.
248pub unsafe fn from_ffi(array: FFI_ArrowArray, schema: &FFI_ArrowSchema) -> Result<ArrayData> {
249    let dt = DataType::try_from(schema)?;
250    let array = Arc::new(array);
251    let tmp = ImportedArrowArray {
252        array: &array,
253        data_type: dt,
254        owner: &array,
255    };
256    // `consume` aligns under-aligned buffers before validating them.
257    tmp.consume()
258}
259
260/// Import [ArrayData] from the C Data Interface
261///
262/// # Safety
263///
264/// This struct assumes that the incoming data agrees with the C data interface.
265pub unsafe fn from_ffi_and_data_type(
266    array: FFI_ArrowArray,
267    data_type: DataType,
268) -> Result<ArrayData> {
269    let array = Arc::new(array);
270    let tmp = ImportedArrowArray {
271        array: &array,
272        data_type,
273        owner: &array,
274    };
275    // `consume` aligns under-aligned buffers before validating them.
276    tmp.consume()
277}
278
279#[derive(Debug)]
280struct ImportedArrowArray<'a> {
281    array: &'a FFI_ArrowArray,
282    data_type: DataType,
283    owner: &'a Arc<FFI_ArrowArray>,
284}
285
286impl ImportedArrowArray<'_> {
287    fn consume(self) -> Result<ArrayData> {
288        let len = self.array.len();
289        let offset = self.array.offset();
290        let null_count = match &self.data_type {
291            DataType::Null => Some(0),
292            _ => self.array.null_count_opt(),
293        };
294
295        let data_layout = layout(&self.data_type);
296        let buffers = self.buffers(data_layout.can_contain_null_mask, data_layout.variadic)?;
297
298        let null_bit_buffer = if data_layout.can_contain_null_mask {
299            self.null_bit_buffer()
300        } else {
301            None
302        };
303
304        let mut child_data = self.consume_children()?;
305
306        if let Some(d) = self.dictionary()? {
307            // For dictionary type there should only be a single child, so we don't need to worry if
308            // there are other children added above.
309            assert!(child_data.is_empty());
310            child_data.push(d.consume()?);
311        }
312
313        // Align before validate: spec-legal 8-byte-aligned buffers (e.g. Decimal128
314        // from JVM) get realigned rather than rejected, even under `force_validate`.
315        // Mirrors the IPC reader. See #10034.
316        let mut builder = ArrayData::builder(self.data_type)
317            .len(len)
318            .offset(offset)
319            .null_bit_buffer(null_bit_buffer)
320            .buffers(buffers)
321            .child_data(child_data)
322            .align_buffers(true);
323        // Only set the count if the producer reported one; else `build` recomputes.
324        if let Some(null_count) = null_count {
325            builder = builder.null_count(null_count);
326        }
327        // SAFETY: the caller guarantees the data agrees with the C Data Interface.
328        unsafe { builder.skip_validation(true) }.build()
329    }
330
331    fn consume_children(&self) -> Result<Vec<ArrayData>> {
332        match &self.data_type {
333            DataType::List(field)
334            | DataType::FixedSizeList(field, _)
335            | DataType::LargeList(field)
336            | DataType::ListView(field)
337            | DataType::LargeListView(field)
338            | DataType::Map(field, _) => Ok([self.consume_child(0, field.data_type())?].to_vec()),
339            DataType::Struct(fields) => {
340                assert_eq!(fields.len(), self.array.num_children());
341                fields
342                    .iter()
343                    .enumerate()
344                    .map(|(i, field)| self.consume_child(i, field.data_type()))
345                    .collect::<Result<Vec<_>>>()
346            }
347            DataType::Union(union_fields, _) => {
348                assert_eq!(union_fields.len(), self.array.num_children());
349                union_fields
350                    .iter()
351                    .enumerate()
352                    .map(|(i, (_, field))| self.consume_child(i, field.data_type()))
353                    .collect::<Result<Vec<_>>>()
354            }
355            DataType::RunEndEncoded(run_ends_field, values_field) => Ok([
356                self.consume_child(0, run_ends_field.data_type())?,
357                self.consume_child(1, values_field.data_type())?,
358            ]
359            .to_vec()),
360            _ => Ok(Vec::new()),
361        }
362    }
363
364    fn consume_child(&self, index: usize, child_type: &DataType) -> Result<ArrayData> {
365        ImportedArrowArray {
366            array: self.array.child(index),
367            data_type: child_type.clone(),
368            owner: self.owner,
369        }
370        .consume()
371    }
372
373    /// returns all buffers, as organized by Rust (i.e. null buffer is skipped if it's present
374    /// in the spec of the type)
375    fn buffers(&self, can_contain_null_mask: bool, variadic: bool) -> Result<Vec<Buffer>> {
376        // + 1: skip null buffer
377        let buffer_begin = can_contain_null_mask as usize;
378        let buffer_end = self.array.num_buffers() - usize::from(variadic);
379
380        let variadic_buffer_lens = if variadic {
381            // Each views array has 1 (optional) null buffer, 1 views buffer, 1 lengths buffer.
382            // Rest are variadic.
383            let num_variadic_buffers =
384                self.array.num_buffers() - (2 + usize::from(can_contain_null_mask));
385            if num_variadic_buffers == 0 {
386                &[]
387            } else {
388                let lengths = self.array.buffer(self.array.num_buffers() - 1);
389                // SAFETY: is lengths is non-null, then it must be valid for up to num_variadic_buffers.
390                // The C data interface requires buffers to be aligned for their type.
391                #[expect(
392                    clippy::cast_ptr_alignment,
393                    reason = "the C data interface requires aligned buffers"
394                )]
395                unsafe {
396                    std::slice::from_raw_parts(lengths.cast::<i64>(), num_variadic_buffers)
397                }
398            }
399        } else {
400            &[]
401        };
402
403        (buffer_begin..buffer_end)
404            .map(|index| {
405                let len = self.buffer_len(index, variadic_buffer_lens, &self.data_type)?;
406                match unsafe { create_buffer(self.owner.clone(), self.array, index, len) } {
407                    Some(buf) => {
408                        // External libraries may use a dangling pointer for a buffer with length 0.
409                        // We respect the array length specified in the C Data Interface. Actually,
410                        // if the length is incorrect, we cannot create a correct buffer even if
411                        // the pointer is valid.
412                        if buf.is_empty() {
413                            Ok(MutableBuffer::new(0).into())
414                        } else {
415                            Ok(buf)
416                        }
417                    }
418                    None if len == 0 => {
419                        // Null data buffer, which Rust doesn't allow. So create
420                        // an empty buffer.
421                        Ok(MutableBuffer::new(0).into())
422                    }
423                    None => Err(ArrowError::CDataInterface(format!(
424                        "The external buffer at position {index} is null."
425                    ))),
426                }
427            })
428            .collect()
429    }
430
431    /// Returns the length, in bytes, of the buffer `i` (indexed according to the C data interface)
432    /// Rust implementation uses fixed-sized buffers, which require knowledge of their `len`.
433    /// for variable-sized buffers, such as the second buffer of a stringArray, we need
434    /// to fetch offset buffer's len to build the second buffer.
435    fn buffer_len(
436        &self,
437        i: usize,
438        variadic_buffer_lengths: &[i64],
439        dt: &DataType,
440    ) -> Result<usize> {
441        // Special handling for dictionary type as we only care about the key type in the case.
442        let data_type = match dt {
443            DataType::Dictionary(key_data_type, _) => key_data_type.as_ref(),
444            dt => dt,
445        };
446
447        // `ffi::ArrowArray` records array offset, we need to add it back to the
448        // buffer length to get the actual buffer length.
449        let length = self.array.len() + self.array.offset();
450
451        // Inner type is not important for buffer length.
452        Ok(match (&data_type, i) {
453            (
454                DataType::Utf8
455                | DataType::LargeUtf8
456                | DataType::Binary
457                | DataType::LargeBinary
458                | DataType::List(_)
459                | DataType::LargeList(_)
460                | DataType::Map(_, _),
461                1,
462            ) => {
463                // the len of the offset buffer (buffer 1) equals length + 1
464                let bits = bit_width(data_type, i)?;
465                debug_assert_eq!(bits % 8, 0);
466                (length + 1) * (bits / 8)
467            }
468            (DataType::ListView(_) | DataType::LargeListView(_), 1 | 2) => {
469                let bits = bit_width(data_type, i)?;
470                debug_assert_eq!(bits % 8, 0);
471                length * (bits / 8)
472            }
473            (DataType::Utf8 | DataType::Binary, 2) => {
474                // We can short circuit for empty arrays with offset 0 since we know
475                // the values buffer must also be empty, and the single offset present
476                // in the offsets buffer can be an arbitrary value from the producer.
477                //
478                // If the array is empty yet has a non-zero offset, the C data interface
479                // guarantees there are `length + offset` values encoded in the buffer,
480                // so we must find the real size of the values buffer from the offsets
481                // buffer.
482                if self.array.is_empty() && self.array.offset() == 0 {
483                    return Ok(0);
484                }
485
486                // the len of the data buffer (buffer 2) equals the last value of the offset buffer (buffer 1)
487                let len = self.buffer_len(1, variadic_buffer_lengths, dt)?;
488                // first buffer is the null buffer => add(1)
489                // we assume that pointer is aligned for `i32`, as Utf8 uses `i32` offsets.
490                #[expect(clippy::cast_ptr_alignment)]
491                let offset_buffer = self.array.buffer(1).cast::<i32>();
492                // Safety: `len` is the byte length of the offset buffer; dividing by `size_of::<i32>()`
493                // gives the number of i32 elements. The `- 1` is safe because the offset buffer
494                // is always non-empty.
495                (unsafe { *offset_buffer.add(len / size_of::<i32>() - 1) }) as usize
496            }
497            (DataType::LargeUtf8 | DataType::LargeBinary, 2) => {
498                // See the note on the `Utf8` / `Binary` arm above.
499                if self.array.is_empty() && self.array.offset() == 0 {
500                    return Ok(0);
501                }
502
503                // the len of the data buffer (buffer 2) equals the last value of the offset buffer (buffer 1)
504                let len = self.buffer_len(1, variadic_buffer_lengths, dt)?;
505                // first buffer is the null buffer => add(1)
506                // we assume that pointer is aligned for `i64`, as Large uses `i64` offsets.
507                #[expect(clippy::cast_ptr_alignment)]
508                let offset_buffer = self.array.buffer(1).cast::<i64>();
509                // Safety: same as the i32 case above but for i64 offsets.
510                (unsafe { *offset_buffer.add(len / size_of::<i64>() - 1) }) as usize
511            }
512            // View types: these have variadic buffers.
513            // Buffer 1 is the views buffer, which stores 1 u128 per length of the array.
514            // Buffers 2..N-1 are the buffers holding the byte data. Their lengths are variable.
515            // Buffer N is of length (N - 2) and stores i64 containing the lengths of buffers 2..N-1
516            (DataType::Utf8View | DataType::BinaryView, 1) => std::mem::size_of::<u128>() * length,
517            (DataType::Utf8View | DataType::BinaryView, i) => {
518                variadic_buffer_lengths[i - 2] as usize
519            }
520            // buffer len of primitive types
521            _ => {
522                let bits = bit_width(data_type, i)?;
523                bit_util::ceil(length * bits, 8)
524            }
525        })
526    }
527
528    /// returns the null bit buffer.
529    /// Rust implementation uses a buffer that is not part of the array of buffers.
530    /// The C Data interface's null buffer is part of the array of buffers.
531    fn null_bit_buffer(&self) -> Option<Buffer> {
532        // similar to `self.buffer_len(0)`, but without `Result`.
533        // `ffi::ArrowArray` records array offset, we need to add it back to the
534        // buffer length to get the actual buffer length.
535        let length = self.array.len() + self.array.offset();
536        let buffer_len = bit_util::ceil(length, 8);
537
538        unsafe { create_buffer(self.owner.clone(), self.array, 0, buffer_len) }
539    }
540
541    fn dictionary(&self) -> Result<Option<ImportedArrowArray<'_>>> {
542        match (self.array.dictionary(), &self.data_type) {
543            (Some(array), DataType::Dictionary(_, value_type)) => Ok(Some(ImportedArrowArray {
544                array,
545                data_type: value_type.as_ref().clone(),
546                owner: self.owner,
547            })),
548            (Some(_), _) => Err(ArrowError::CDataInterface(
549                "Got dictionary in FFI_ArrowArray for non-dictionary data type".to_string(),
550            )),
551            (None, DataType::Dictionary(_, _)) => Err(ArrowError::CDataInterface(
552                "Missing dictionary in FFI_ArrowArray for dictionary data type".to_string(),
553            )),
554            (_, _) => Ok(None),
555        }
556    }
557}
558
559#[cfg(test)]
560mod tests_to_then_from_ffi {
561    use std::collections::HashMap;
562    use std::mem::ManuallyDrop;
563
564    use arrow_buffer::{ArrowNativeType, NullBuffer};
565    use arrow_schema::Field;
566
567    use crate::builder::UnionBuilder;
568    use crate::cast::AsArray;
569    use crate::types::{Float64Type, Int8Type, Int32Type};
570    use crate::*;
571
572    use super::*;
573
574    #[test]
575    fn test_round_trip() {
576        // create an array natively
577        let array = Int32Array::from(vec![1, 2, 3]);
578
579        // export it
580        let (array, schema) = to_ffi(&array.into_data()).unwrap();
581
582        // (simulate consumer) import it
583        let array = Int32Array::from(unsafe { from_ffi(array, &schema) }.unwrap());
584
585        // verify
586        assert_eq!(array, Int32Array::from(vec![1, 2, 3]));
587    }
588
589    #[test]
590    fn test_import() {
591        // Model receiving const pointers from an external system
592
593        // Create an array natively
594        let data = Int32Array::from(vec![1, 2, 3]).into_data();
595        let schema = FFI_ArrowSchema::try_from(data.data_type()).unwrap();
596        let array = FFI_ArrowArray::new(&data);
597
598        // Use ManuallyDrop to avoid Box:Drop recursing
599        let schema = Box::new(ManuallyDrop::new(schema));
600        let array = Box::new(ManuallyDrop::new(array));
601
602        let schema_ptr = std::ptr::from_ref(&**schema);
603        let array_ptr = std::ptr::from_ref(&**array);
604
605        // We can read them back to memory
606        // SAFETY:
607        // Pointers are aligned and valid
608        let data =
609            unsafe { from_ffi(std::ptr::read(array_ptr), &std::ptr::read(schema_ptr)).unwrap() };
610
611        let array = Int32Array::from(data);
612        assert_eq!(array, Int32Array::from(vec![1, 2, 3]));
613    }
614
615    #[test]
616    fn test_round_trip_with_offset() -> Result<()> {
617        // create an array natively
618        let array = Int32Array::from(vec![Some(1), Some(2), None, Some(3), None]);
619
620        let array = array.slice(1, 2);
621
622        // export it
623        let (array, schema) = to_ffi(&array.to_data())?;
624
625        // (simulate consumer) import it
626        let data = unsafe { from_ffi(array, &schema) }?;
627        let array = make_array(data);
628        let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
629
630        assert_eq!(array, &Int32Array::from(vec![Some(2), None]));
631
632        // (drop/release)
633        Ok(())
634    }
635
636    #[test]
637    #[cfg(not(feature = "force_validate"))]
638    fn test_decimal_round_trip() -> Result<()> {
639        // create an array natively
640        let original_array = [Some(12345_i128), Some(-12345_i128), None]
641            .into_iter()
642            .collect::<Decimal128Array>()
643            .with_precision_and_scale(6, 2)
644            .unwrap();
645
646        // export it
647        let (array, schema) = to_ffi(&original_array.to_data())?;
648
649        // (simulate consumer) import it
650        let data = unsafe { from_ffi(array, &schema) }?;
651        let array = make_array(data);
652
653        // perform some operation
654        let array = array.as_any().downcast_ref::<Decimal128Array>().unwrap();
655
656        // verify
657        assert_eq!(array, &original_array);
658
659        // (drop/release)
660        Ok(())
661    }
662    // case with nulls is tested in the docs, through the example on this module.
663
664    #[test]
665    fn test_decimal128_under_aligned_import() -> Result<()> {
666        // FixedSizeBinary(16) needs only 1-byte alignment so it builds cleanly
667        // even under force_validate; imported as Decimal128 it triggers the
668        // realignment path. Regression test for #10034.
669        let aligned = Buffer::from_vec(vec![0_i128, 1_i128, 2_i128]);
670        let under_aligned = aligned.slice(8);
671        assert_eq!(under_aligned.as_ptr().align_offset(8), 0);
672        assert_ne!(under_aligned.as_ptr().align_offset(16), 0);
673
674        let data = ArrayData::builder(DataType::FixedSizeBinary(16))
675            .len(2)
676            .add_buffer(under_aligned)
677            .build()?;
678
679        let array = FFI_ArrowArray::new(&data);
680        let imported = unsafe { from_ffi_and_data_type(array, DataType::Decimal128(10, 2)) }?;
681        let array = Decimal128Array::from(imported);
682
683        // slicing at byte 8 into [0i128, 1, 2] yields elements 1<<64 and 2<<64.
684        assert_eq!(array.len(), 2);
685        assert_eq!(array.value(0), 1_i128 << 64);
686        assert_eq!(array.value(1), 2_i128 << 64);
687        Ok(())
688    }
689
690    #[test]
691    fn test_null_count_handling() {
692        let int32_data = ArrayData::builder(DataType::Int32)
693            .len(10)
694            .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))
695            .null_bit_buffer(Some(Buffer::from([0b01011111, 0b00000001])))
696            .build()
697            .unwrap();
698        let mut ffi_array = FFI_ArrowArray::new(&int32_data);
699        assert_eq!(3, ffi_array.null_count());
700        assert_eq!(Some(3), ffi_array.null_count_opt());
701        // Simulating uninitialized state
702        unsafe {
703            ffi_array.set_null_count(-1);
704        }
705        assert_eq!(None, ffi_array.null_count_opt());
706        let int32_data = unsafe { from_ffi_and_data_type(ffi_array, DataType::Int32) }.unwrap();
707        assert_eq!(3, int32_data.null_count());
708
709        let null_data = &ArrayData::new_null(&DataType::Null, 10);
710        let mut ffi_array = FFI_ArrowArray::new(null_data);
711        assert_eq!(10, ffi_array.null_count());
712        assert_eq!(Some(10), ffi_array.null_count_opt());
713        // Simulating uninitialized state
714        unsafe {
715            ffi_array.set_null_count(-1);
716        }
717        assert_eq!(None, ffi_array.null_count_opt());
718        let null_data = unsafe { from_ffi_and_data_type(ffi_array, DataType::Null) }.unwrap();
719        assert_eq!(0, null_data.null_count());
720    }
721
722    fn test_generic_string<Offset: OffsetSizeTrait>() -> Result<()> {
723        // create an array natively
724        let array = GenericStringArray::<Offset>::from(vec![Some("a"), None, Some("aaa")]);
725
726        // export it
727        let (array, schema) = to_ffi(&array.to_data())?;
728
729        // (simulate consumer) import it
730        let data = unsafe { from_ffi(array, &schema) }?;
731        let array = make_array(data);
732
733        // perform some operation
734        let array = array
735            .as_any()
736            .downcast_ref::<GenericStringArray<Offset>>()
737            .unwrap();
738
739        // verify
740        let expected = GenericStringArray::<Offset>::from(vec![Some("a"), None, Some("aaa")]);
741        assert_eq!(array, &expected);
742
743        // (drop/release)
744        Ok(())
745    }
746
747    #[test]
748    fn test_string() -> Result<()> {
749        test_generic_string::<i32>()
750    }
751
752    #[test]
753    fn test_large_string() -> Result<()> {
754        test_generic_string::<i64>()
755    }
756
757    fn test_generic_list<Offset: OffsetSizeTrait>() -> Result<()> {
758        // Construct a value array
759        let value_data = ArrayData::builder(DataType::Int32)
760            .len(8)
761            .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5, 6, 7]))
762            .build()
763            .unwrap();
764
765        // Construct a buffer for value offsets, for the nested array:
766        //  [[0, 1, 2], [3, 4, 5], [6, 7]]
767        let value_offsets = [0_usize, 3, 6, 8]
768            .iter()
769            .map(|i| Offset::from_usize(*i).unwrap())
770            .collect::<Buffer>();
771
772        // Construct a list array from the above two
773        let list_data_type = GenericListArray::<Offset>::DATA_TYPE_CONSTRUCTOR(Arc::new(
774            Field::new_list_field(DataType::Int32, false),
775        ));
776
777        let list_data = ArrayData::builder(list_data_type)
778            .len(3)
779            .add_buffer(value_offsets)
780            .add_child_data(value_data)
781            .build()
782            .unwrap();
783
784        // create an array natively
785        let array = GenericListArray::<Offset>::from(list_data.clone());
786
787        // export it
788        let (array, schema) = to_ffi(&array.to_data())?;
789
790        // (simulate consumer) import it
791        let data = unsafe { from_ffi(array, &schema) }?;
792        let array = make_array(data);
793
794        // downcast
795        let array = array
796            .as_any()
797            .downcast_ref::<GenericListArray<Offset>>()
798            .unwrap();
799
800        // verify
801        let expected = GenericListArray::<Offset>::from(list_data);
802        assert_eq!(&array.value(0), &expected.value(0));
803        assert_eq!(&array.value(1), &expected.value(1));
804        assert_eq!(&array.value(2), &expected.value(2));
805
806        // (drop/release)
807        Ok(())
808    }
809
810    #[test]
811    fn test_list() -> Result<()> {
812        test_generic_list::<i32>()
813    }
814
815    #[test]
816    fn test_large_list() -> Result<()> {
817        test_generic_list::<i64>()
818    }
819
820    fn test_generic_list_view<Offset: OffsetSizeTrait + ArrowNativeType>() -> Result<()> {
821        // Construct a value array
822        let value_data = ArrayData::builder(DataType::Int16)
823            .len(8)
824            .add_buffer(Buffer::from_slice_ref([0_i16, 1, 2, 3, 4, 5, 6, 7]))
825            .build()
826            .unwrap();
827
828        // Construct a buffer for value offsets, for the nested array:
829        //  [[0, 1, 2], [3, 4, 5], [6, 7]]
830        let value_offsets = [0_usize, 3, 6]
831            .iter()
832            .map(|i| Offset::from_usize(*i).unwrap())
833            .collect::<Buffer>();
834
835        let sizes_buffer = [3_usize, 3, 2]
836            .iter()
837            .map(|i| Offset::from_usize(*i).unwrap())
838            .collect::<Buffer>();
839
840        // Construct a list array from the above two
841        let list_view_dt = GenericListViewArray::<Offset>::DATA_TYPE_CONSTRUCTOR(Arc::new(
842            Field::new_list_field(DataType::Int16, false),
843        ));
844
845        let list_data = ArrayData::builder(list_view_dt)
846            .len(3)
847            .add_buffer(value_offsets)
848            .add_buffer(sizes_buffer)
849            .add_child_data(value_data)
850            .build()
851            .unwrap();
852
853        let original = GenericListViewArray::<Offset>::from(list_data.clone());
854
855        // export it
856        let (array, schema) = to_ffi(&original.to_data())?;
857
858        // (simulate consumer) import it
859        let data = unsafe { from_ffi(array, &schema) }?;
860        let array = make_array(data);
861
862        // downcast
863        let array = array
864            .as_any()
865            .downcast_ref::<GenericListViewArray<Offset>>()
866            .unwrap();
867
868        assert_eq!(&array.value(0), &original.value(0));
869        assert_eq!(&array.value(1), &original.value(1));
870        assert_eq!(&array.value(2), &original.value(2));
871
872        Ok(())
873    }
874
875    #[test]
876    fn test_list_view() -> Result<()> {
877        test_generic_list_view::<i32>()
878    }
879
880    #[test]
881    fn test_large_list_view() -> Result<()> {
882        test_generic_list_view::<i64>()
883    }
884
885    fn test_generic_binary<Offset: OffsetSizeTrait>() -> Result<()> {
886        // create an array natively
887        let array: Vec<Option<&[u8]>> = vec![Some(b"a"), None, Some(b"aaa")];
888        let array = GenericBinaryArray::<Offset>::from(array);
889
890        // export it
891        let (array, schema) = to_ffi(&array.to_data())?;
892
893        // (simulate consumer) import it
894        let data = unsafe { from_ffi(array, &schema) }?;
895        let array = make_array(data);
896        let array = array
897            .as_any()
898            .downcast_ref::<GenericBinaryArray<Offset>>()
899            .unwrap();
900
901        // verify
902        let expected: Vec<Option<&[u8]>> = vec![Some(b"a"), None, Some(b"aaa")];
903        let expected = GenericBinaryArray::<Offset>::from(expected);
904        assert_eq!(array, &expected);
905
906        // (drop/release)
907        Ok(())
908    }
909
910    #[test]
911    fn test_binary() -> Result<()> {
912        test_generic_binary::<i32>()
913    }
914
915    #[test]
916    fn test_large_binary() -> Result<()> {
917        test_generic_binary::<i64>()
918    }
919
920    #[test]
921    fn test_bool() -> Result<()> {
922        // create an array natively
923        let array = BooleanArray::from(vec![None, Some(true), Some(false)]);
924
925        // export it
926        let (array, schema) = to_ffi(&array.to_data())?;
927
928        // (simulate consumer) import it
929        let data = unsafe { from_ffi(array, &schema) }?;
930        let array = make_array(data);
931        let array = array.as_any().downcast_ref::<BooleanArray>().unwrap();
932
933        // verify
934        assert_eq!(
935            array,
936            &BooleanArray::from(vec![None, Some(true), Some(false)])
937        );
938
939        // (drop/release)
940        Ok(())
941    }
942
943    #[test]
944    fn test_time32() -> Result<()> {
945        // create an array natively
946        let array = Time32MillisecondArray::from(vec![None, Some(1), Some(2)]);
947
948        // export it
949        let (array, schema) = to_ffi(&array.to_data())?;
950
951        // (simulate consumer) import it
952        let data = unsafe { from_ffi(array, &schema) }?;
953        let array = make_array(data);
954        let array = array
955            .as_any()
956            .downcast_ref::<Time32MillisecondArray>()
957            .unwrap();
958
959        // verify
960        assert_eq!(
961            array,
962            &Time32MillisecondArray::from(vec![None, Some(1), Some(2)])
963        );
964
965        // (drop/release)
966        Ok(())
967    }
968
969    #[test]
970    fn test_timestamp() -> Result<()> {
971        // create an array natively
972        let array = TimestampMillisecondArray::from(vec![None, Some(1), Some(2)]);
973
974        // export it
975        let (array, schema) = to_ffi(&array.to_data())?;
976
977        // (simulate consumer) import it
978        let data = unsafe { from_ffi(array, &schema) }?;
979        let array = make_array(data);
980        let array = array
981            .as_any()
982            .downcast_ref::<TimestampMillisecondArray>()
983            .unwrap();
984
985        // verify
986        assert_eq!(
987            array,
988            &TimestampMillisecondArray::from(vec![None, Some(1), Some(2)])
989        );
990
991        // (drop/release)
992        Ok(())
993    }
994
995    #[test]
996    fn test_fixed_size_binary_array() -> Result<()> {
997        let values = vec![
998            None,
999            Some(vec![10, 10, 10]),
1000            None,
1001            Some(vec![20, 20, 20]),
1002            Some(vec![30, 30, 30]),
1003            None,
1004        ];
1005        let array = FixedSizeBinaryArray::try_from_sparse_iter_with_size(values.into_iter(), 3)?;
1006
1007        // export it
1008        let (array, schema) = to_ffi(&array.to_data())?;
1009
1010        // (simulate consumer) import it
1011        let data = unsafe { from_ffi(array, &schema) }?;
1012        let array = make_array(data);
1013        let array = array
1014            .as_any()
1015            .downcast_ref::<FixedSizeBinaryArray>()
1016            .unwrap();
1017
1018        // verify
1019        assert_eq!(
1020            array,
1021            &FixedSizeBinaryArray::try_from_sparse_iter_with_size(
1022                vec![
1023                    None,
1024                    Some(vec![10, 10, 10]),
1025                    None,
1026                    Some(vec![20, 20, 20]),
1027                    Some(vec![30, 30, 30]),
1028                    None,
1029                ]
1030                .into_iter(),
1031                3
1032            )?
1033        );
1034
1035        // (drop/release)
1036        Ok(())
1037    }
1038
1039    #[test]
1040    fn test_fixed_size_list_array() -> Result<()> {
1041        // 0000 0100
1042        let mut validity_bits: [u8; 1] = [0; 1];
1043        bit_util::set_bit(&mut validity_bits, 2);
1044
1045        let v: Vec<i32> = (0..9).collect();
1046        let value_data = ArrayData::builder(DataType::Int32)
1047            .len(9)
1048            .add_buffer(Buffer::from_slice_ref(&v))
1049            .build()?;
1050
1051        let list_data_type =
1052            DataType::FixedSizeList(Arc::new(Field::new("f", DataType::Int32, false)), 3);
1053        let list_data = ArrayData::builder(list_data_type.clone())
1054            .len(3)
1055            .null_bit_buffer(Some(Buffer::from(validity_bits)))
1056            .add_child_data(value_data)
1057            .build()?;
1058
1059        // export it
1060        let (array, schema) = to_ffi(&list_data)?;
1061
1062        // (simulate consumer) import it
1063        let data = unsafe { from_ffi(array, &schema) }?;
1064        let array = make_array(data);
1065        let array = array.as_any().downcast_ref::<FixedSizeListArray>().unwrap();
1066
1067        // 0010 0100
1068        let mut expected_validity_bits: [u8; 1] = [0; 1];
1069        bit_util::set_bit(&mut expected_validity_bits, 2);
1070        bit_util::set_bit(&mut expected_validity_bits, 5);
1071
1072        let mut w = vec![];
1073        w.extend_from_slice(&v);
1074
1075        let expected_value_data = ArrayData::builder(DataType::Int32)
1076            .len(9)
1077            .add_buffer(Buffer::from_slice_ref(&w))
1078            .build()?;
1079
1080        let expected_list_data = ArrayData::builder(list_data_type)
1081            .len(3)
1082            .null_bit_buffer(Some(Buffer::from(expected_validity_bits)))
1083            .add_child_data(expected_value_data)
1084            .build()?;
1085        let expected_array = FixedSizeListArray::from(expected_list_data);
1086
1087        // verify
1088        assert_eq!(array, &expected_array);
1089
1090        // (drop/release)
1091        Ok(())
1092    }
1093
1094    #[test]
1095    fn test_dictionary() -> Result<()> {
1096        // create an array natively
1097        let values = vec!["a", "aaa", "aaa"];
1098        let dict_array: DictionaryArray<Int8Type> = values.into_iter().collect();
1099
1100        // export it
1101        let (array, schema) = to_ffi(&dict_array.to_data())?;
1102
1103        // (simulate consumer) import it
1104        let data = unsafe { from_ffi(array, &schema) }?;
1105        let array = make_array(data);
1106        let actual = array
1107            .as_any()
1108            .downcast_ref::<DictionaryArray<Int8Type>>()
1109            .unwrap();
1110
1111        // verify
1112        let new_values = vec!["a", "aaa", "aaa"];
1113        let expected: DictionaryArray<Int8Type> = new_values.into_iter().collect();
1114        assert_eq!(actual, &expected);
1115
1116        // (drop/release)
1117        Ok(())
1118    }
1119
1120    #[test]
1121    fn test_duration() -> Result<()> {
1122        // create an array natively
1123        let array = DurationSecondArray::from(vec![None, Some(1), Some(2)]);
1124
1125        // export it
1126        let (array, schema) = to_ffi(&array.to_data())?;
1127
1128        // (simulate consumer) import it
1129        let data = unsafe { from_ffi(array, &schema) }?;
1130        let array = make_array(data);
1131        let array = array
1132            .as_any()
1133            .downcast_ref::<DurationSecondArray>()
1134            .unwrap();
1135
1136        // verify
1137        assert_eq!(
1138            array,
1139            &DurationSecondArray::from(vec![None, Some(1), Some(2)])
1140        );
1141
1142        // (drop/release)
1143        Ok(())
1144    }
1145
1146    #[test]
1147    fn test_map_array() -> Result<()> {
1148        let keys = vec!["a", "b", "c", "d", "e", "f", "g", "h"];
1149        let values_data = UInt32Array::from(vec![0u32, 10, 20, 30, 40, 50, 60, 70]);
1150
1151        // Construct a buffer for value offsets, for the nested array:
1152        //  [[a, b, c], [d, e, f], [g, h]]
1153        let entry_offsets = [0, 3, 6, 8];
1154
1155        let map_array =
1156            MapArray::new_from_strings(keys.clone().into_iter(), &values_data, &entry_offsets)
1157                .unwrap();
1158
1159        // export it
1160        let (array, schema) = to_ffi(&map_array.to_data())?;
1161
1162        // (simulate consumer) import it
1163        let data = unsafe { from_ffi(array, &schema) }?;
1164        let array = make_array(data);
1165
1166        // perform some operation
1167        let array = array.as_any().downcast_ref::<MapArray>().unwrap();
1168        assert_eq!(array, &map_array);
1169
1170        Ok(())
1171    }
1172
1173    #[test]
1174    fn test_struct_array() -> Result<()> {
1175        let metadata: HashMap<String, String> =
1176            [("Hello".to_string(), "World! 😊".to_string())].into();
1177        let struct_array = StructArray::from(vec![(
1178            Arc::new(Field::new("a", DataType::Int32, false).with_metadata(metadata)),
1179            Arc::new(Int32Array::from(vec![2, 4, 6])) as Arc<dyn Array>,
1180        )]);
1181
1182        // export it
1183        let (array, schema) = to_ffi(&struct_array.to_data())?;
1184
1185        // (simulate consumer) import it
1186        let data = unsafe { from_ffi(array, &schema) }?;
1187        let array = make_array(data);
1188
1189        // perform some operation
1190        let array = array.as_any().downcast_ref::<StructArray>().unwrap();
1191        assert_eq!(array.data_type(), struct_array.data_type());
1192        assert_eq!(array, &struct_array);
1193
1194        Ok(())
1195    }
1196
1197    #[test]
1198    fn test_union_sparse_array() -> Result<()> {
1199        let mut builder = UnionBuilder::new_sparse();
1200        builder.append::<Int32Type>("a", 1).unwrap();
1201        builder.append_null::<Int32Type>("a").unwrap();
1202        builder.append::<Float64Type>("c", 3.0).unwrap();
1203        builder.append::<Int32Type>("a", 4).unwrap();
1204        let union = builder.build().unwrap();
1205
1206        // export it
1207        let (array, schema) = to_ffi(&union.to_data())?;
1208
1209        // (simulate consumer) import it
1210        let data = unsafe { from_ffi(array, &schema) }?;
1211        let array = make_array(data);
1212
1213        let array = array.as_any().downcast_ref::<UnionArray>().unwrap();
1214
1215        let expected_type_ids = vec![0_i8, 0, 1, 0];
1216
1217        // Check type ids
1218        assert_eq!(*array.type_ids(), expected_type_ids);
1219        for (i, id) in expected_type_ids.iter().enumerate() {
1220            assert_eq!(id, &array.type_id(i));
1221        }
1222
1223        // Check offsets, sparse union should only have a single buffer, i.e. no offsets
1224        assert!(array.offsets().is_none());
1225
1226        for i in 0..array.len() {
1227            let slot = array.value(i);
1228            match i {
1229                0 => {
1230                    let slot = slot.as_primitive::<Int32Type>();
1231                    assert!(!slot.is_null(0));
1232                    assert_eq!(slot.len(), 1);
1233                    let value = slot.value(0);
1234                    assert_eq!(1_i32, value);
1235                }
1236                1 => assert!(slot.is_null(0)),
1237                2 => {
1238                    let slot = slot.as_primitive::<Float64Type>();
1239                    assert!(!slot.is_null(0));
1240                    assert_eq!(slot.len(), 1);
1241                    let value = slot.value(0);
1242                    assert_eq!(value, 3_f64);
1243                }
1244                3 => {
1245                    let slot = slot.as_primitive::<Int32Type>();
1246                    assert!(!slot.is_null(0));
1247                    assert_eq!(slot.len(), 1);
1248                    let value = slot.value(0);
1249                    assert_eq!(4_i32, value);
1250                }
1251                _ => unreachable!(),
1252            }
1253        }
1254
1255        Ok(())
1256    }
1257
1258    #[test]
1259    fn test_union_dense_array() -> Result<()> {
1260        let mut builder = UnionBuilder::new_dense();
1261        builder.append::<Int32Type>("a", 1).unwrap();
1262        builder.append_null::<Int32Type>("a").unwrap();
1263        builder.append::<Float64Type>("c", 3.0).unwrap();
1264        builder.append::<Int32Type>("a", 4).unwrap();
1265        let union = builder.build().unwrap();
1266
1267        // export it
1268        let (array, schema) = to_ffi(&union.to_data())?;
1269
1270        // (simulate consumer) import it
1271        let data = unsafe { from_ffi(array, &schema) }?;
1272        let array = UnionArray::from(data);
1273
1274        let expected_type_ids = vec![0_i8, 0, 1, 0];
1275
1276        // Check type ids
1277        assert_eq!(*array.type_ids(), expected_type_ids);
1278        for (i, id) in expected_type_ids.iter().enumerate() {
1279            assert_eq!(id, &array.type_id(i));
1280        }
1281
1282        assert!(array.offsets().is_some());
1283
1284        for i in 0..array.len() {
1285            let slot = array.value(i);
1286            match i {
1287                0 => {
1288                    let slot = slot.as_primitive::<Int32Type>();
1289                    assert!(!slot.is_null(0));
1290                    assert_eq!(slot.len(), 1);
1291                    let value = slot.value(0);
1292                    assert_eq!(1_i32, value);
1293                }
1294                1 => assert!(slot.is_null(0)),
1295                2 => {
1296                    let slot = slot.as_primitive::<Float64Type>();
1297                    assert!(!slot.is_null(0));
1298                    assert_eq!(slot.len(), 1);
1299                    let value = slot.value(0);
1300                    assert_eq!(value, 3_f64);
1301                }
1302                3 => {
1303                    let slot = slot.as_primitive::<Int32Type>();
1304                    assert!(!slot.is_null(0));
1305                    assert_eq!(slot.len(), 1);
1306                    let value = slot.value(0);
1307                    assert_eq!(4_i32, value);
1308                }
1309                _ => unreachable!(),
1310            }
1311        }
1312
1313        Ok(())
1314    }
1315
1316    #[test]
1317    fn test_run_array() -> Result<()> {
1318        let value_data =
1319            PrimitiveArray::<Int8Type>::from_iter_values([10_i8, 11, 12, 13, 14, 15, 16, 17]);
1320
1321        // Construct a run_ends array:
1322        let run_ends_values = [4_i32, 6, 7, 9, 13, 18, 20, 22];
1323        let run_ends_data =
1324            PrimitiveArray::<Int32Type>::from_iter_values(run_ends_values.iter().copied());
1325
1326        // Construct a run ends encoded array from the above two
1327        let ree_array = RunArray::<Int32Type>::try_new(&run_ends_data, &value_data).unwrap();
1328
1329        // export it
1330        let (array, schema) = to_ffi(&ree_array.to_data())?;
1331
1332        // (simulate consumer) import it
1333        let data = unsafe { from_ffi(array, &schema) }?;
1334        let array = make_array(data);
1335
1336        // perform some operation
1337        let array = array
1338            .as_any()
1339            .downcast_ref::<RunArray<Int32Type>>()
1340            .unwrap();
1341        assert_eq!(array.data_type(), ree_array.data_type());
1342        assert_eq!(array.run_ends().values(), ree_array.run_ends().values());
1343        assert_eq!(array.values(), ree_array.values());
1344
1345        Ok(())
1346    }
1347
1348    #[test]
1349    fn test_nullable_run_array() -> Result<()> {
1350        let nulls = NullBuffer::from(vec![true, false, true, true, false]);
1351        let value_data =
1352            PrimitiveArray::<Int8Type>::new(vec![1_i8, 2, 3, 4, 5].into(), Some(nulls));
1353
1354        // Construct a run_ends array:
1355        let run_ends_values = [5_i32, 6, 7, 8, 10];
1356        let run_ends_data =
1357            PrimitiveArray::<Int32Type>::from_iter_values(run_ends_values.iter().copied());
1358
1359        // Construct a run ends encoded array from the above two
1360        let ree_array = RunArray::<Int32Type>::try_new(&run_ends_data, &value_data).unwrap();
1361
1362        // export it
1363        let (array, schema) = to_ffi(&ree_array.to_data())?;
1364
1365        // (simulate consumer) import it
1366        let data = unsafe { from_ffi(array, &schema) }?;
1367        let array = make_array(data);
1368
1369        // perform some operation
1370        let array = array
1371            .as_any()
1372            .downcast_ref::<RunArray<Int32Type>>()
1373            .unwrap();
1374        assert_eq!(array.data_type(), ree_array.data_type());
1375        assert_eq!(array.run_ends().values(), ree_array.run_ends().values());
1376        assert_eq!(array.values(), ree_array.values());
1377
1378        Ok(())
1379    }
1380}
1381
1382#[cfg(test)]
1383mod tests_from_ffi {
1384    #[cfg(not(feature = "force_validate"))]
1385    use std::ptr::NonNull;
1386    use std::sync::Arc;
1387
1388    use arrow_buffer::NullBuffer;
1389    #[cfg(not(feature = "force_validate"))]
1390    use arrow_buffer::{ScalarBuffer, bit_util, buffer::Buffer};
1391    #[cfg(feature = "force_validate")]
1392    use arrow_buffer::{bit_util, buffer::Buffer};
1393
1394    use arrow_data::ArrayData;
1395    use arrow_data::transform::MutableArrayData;
1396    use arrow_schema::{DataType, Field};
1397
1398    use super::Result;
1399
1400    use crate::builder::GenericByteViewBuilder;
1401    use crate::types::{BinaryViewType, ByteViewType, Int32Type, StringViewType};
1402    use crate::{
1403        ArrayRef, GenericByteViewArray, ListArray,
1404        array::{
1405            Array, BooleanArray, DictionaryArray, FixedSizeBinaryArray, FixedSizeListArray,
1406            Int32Array, Int64Array, StringArray, StructArray, UInt32Array, UInt64Array,
1407        },
1408        ffi::{FFI_ArrowArray, FFI_ArrowSchema, from_ffi},
1409        make_array,
1410    };
1411
1412    fn test_round_trip(expected: &ArrayData) -> Result<()> {
1413        // here we export the array
1414        let array = FFI_ArrowArray::new(expected);
1415        let schema = FFI_ArrowSchema::try_from(expected.data_type())?;
1416
1417        // simulate an external consumer by being the consumer
1418        let result = &unsafe { from_ffi(array, &schema) }?;
1419
1420        assert_eq!(result, expected);
1421        Ok(())
1422    }
1423
1424    #[test]
1425    fn test_u32() -> Result<()> {
1426        let array = UInt32Array::from(vec![Some(2), None, Some(1), None]);
1427        let data = array.into_data();
1428        test_round_trip(&data)
1429    }
1430
1431    #[test]
1432    fn test_u64() -> Result<()> {
1433        let array = UInt64Array::from(vec![Some(2), None, Some(1), None]);
1434        let data = array.into_data();
1435        test_round_trip(&data)
1436    }
1437
1438    #[test]
1439    fn test_i64() -> Result<()> {
1440        let array = Int64Array::from(vec![Some(2), None, Some(1), None]);
1441        let data = array.into_data();
1442        test_round_trip(&data)
1443    }
1444
1445    #[test]
1446    fn test_struct() -> Result<()> {
1447        let inner = StructArray::from(vec![
1448            (
1449                Arc::new(Field::new("a1", DataType::Boolean, false)),
1450                Arc::new(BooleanArray::from(vec![true, true, false, false])) as Arc<dyn Array>,
1451            ),
1452            (
1453                Arc::new(Field::new("a2", DataType::UInt32, false)),
1454                Arc::new(UInt32Array::from(vec![1, 2, 3, 4])),
1455            ),
1456        ]);
1457
1458        let array = StructArray::from(vec![
1459            (
1460                Arc::new(Field::new("a", inner.data_type().clone(), false)),
1461                Arc::new(inner) as Arc<dyn Array>,
1462            ),
1463            (
1464                Arc::new(Field::new("b", DataType::Boolean, false)),
1465                Arc::new(BooleanArray::from(vec![false, false, true, true])) as Arc<dyn Array>,
1466            ),
1467            (
1468                Arc::new(Field::new("c", DataType::UInt32, false)),
1469                Arc::new(UInt32Array::from(vec![42, 28, 19, 31])),
1470            ),
1471        ]);
1472        let data = array.into_data();
1473        test_round_trip(&data)
1474    }
1475
1476    #[test]
1477    fn test_dictionary() -> Result<()> {
1478        let values = StringArray::from(vec![Some("foo"), Some("bar"), None]);
1479        let keys = Int32Array::from(vec![
1480            Some(0),
1481            Some(1),
1482            None,
1483            Some(1),
1484            Some(1),
1485            None,
1486            Some(1),
1487            Some(2),
1488            Some(1),
1489            None,
1490        ]);
1491        let array = DictionaryArray::new(keys, Arc::new(values));
1492
1493        let data = array.into_data();
1494        test_round_trip(&data)
1495    }
1496
1497    #[test]
1498    fn test_fixed_size_binary() -> Result<()> {
1499        let values = vec![vec![10, 10, 10], vec![20, 20, 20], vec![30, 30, 30]];
1500        let array = FixedSizeBinaryArray::try_from_iter(values.into_iter())?;
1501
1502        let data = array.into_data();
1503        test_round_trip(&data)
1504    }
1505
1506    #[test]
1507    fn test_fixed_size_binary_with_nulls() -> Result<()> {
1508        let values = vec![
1509            None,
1510            Some(vec![10, 10, 10]),
1511            None,
1512            Some(vec![20, 20, 20]),
1513            Some(vec![30, 30, 30]),
1514            None,
1515        ];
1516        let array = FixedSizeBinaryArray::try_from_sparse_iter_with_size(values.into_iter(), 3)?;
1517
1518        let data = array.into_data();
1519        test_round_trip(&data)
1520    }
1521
1522    #[test]
1523    fn test_fixed_size_list() -> Result<()> {
1524        let v: Vec<i64> = (0..9).collect();
1525        let value_data = ArrayData::builder(DataType::Int64)
1526            .len(9)
1527            .add_buffer(Buffer::from_slice_ref(v))
1528            .build()?;
1529        let list_data_type =
1530            DataType::FixedSizeList(Arc::new(Field::new("f", DataType::Int64, false)), 3);
1531        let list_data = ArrayData::builder(list_data_type)
1532            .len(3)
1533            .add_child_data(value_data)
1534            .build()?;
1535        let array = FixedSizeListArray::from(list_data);
1536
1537        let data = array.into_data();
1538        test_round_trip(&data)
1539    }
1540
1541    #[test]
1542    fn test_fixed_size_list_with_nulls() -> Result<()> {
1543        // 0100 0110
1544        let mut validity_bits: [u8; 1] = [0; 1];
1545        bit_util::set_bit(&mut validity_bits, 1);
1546        bit_util::set_bit(&mut validity_bits, 2);
1547        bit_util::set_bit(&mut validity_bits, 6);
1548
1549        let v: Vec<i16> = (0..16).collect();
1550        let value_data = ArrayData::builder(DataType::Int16)
1551            .len(16)
1552            .add_buffer(Buffer::from_slice_ref(v))
1553            .build()?;
1554        let list_data_type =
1555            DataType::FixedSizeList(Arc::new(Field::new("f", DataType::Int16, false)), 2);
1556        let list_data = ArrayData::builder(list_data_type)
1557            .len(8)
1558            .null_bit_buffer(Some(Buffer::from(validity_bits)))
1559            .add_child_data(value_data)
1560            .build()?;
1561        let array = FixedSizeListArray::from(list_data);
1562
1563        let data = array.into_data();
1564        test_round_trip(&data)
1565    }
1566
1567    #[test]
1568    fn test_fixed_size_list_nested() -> Result<()> {
1569        let v: Vec<i32> = (0..16).collect();
1570        let value_data = ArrayData::builder(DataType::Int32)
1571            .len(16)
1572            .add_buffer(Buffer::from_slice_ref(v))
1573            .build()?;
1574
1575        let offsets: Vec<i32> = vec![0, 2, 4, 6, 8, 10, 12, 14, 16];
1576        let value_offsets = Buffer::from_slice_ref(offsets);
1577        let inner_list_data_type =
1578            DataType::List(Arc::new(Field::new_list_field(DataType::Int32, false)));
1579        let inner_list_data = ArrayData::builder(inner_list_data_type.clone())
1580            .len(8)
1581            .add_buffer(value_offsets)
1582            .add_child_data(value_data)
1583            .build()?;
1584
1585        // 0000 0100
1586        let mut validity_bits: [u8; 1] = [0; 1];
1587        bit_util::set_bit(&mut validity_bits, 2);
1588
1589        let list_data_type =
1590            DataType::FixedSizeList(Arc::new(Field::new("f", inner_list_data_type, false)), 2);
1591        let list_data = ArrayData::builder(list_data_type)
1592            .len(4)
1593            .null_bit_buffer(Some(Buffer::from(validity_bits)))
1594            .add_child_data(inner_list_data)
1595            .build()?;
1596
1597        let array = FixedSizeListArray::from(list_data);
1598
1599        let data = array.into_data();
1600        test_round_trip(&data)
1601    }
1602
1603    #[test]
1604    fn test_list_view() -> Result<()> {
1605        // Construct a value array
1606        let value_data = ArrayData::builder(DataType::Int16)
1607            .len(8)
1608            .add_buffer(Buffer::from_slice_ref([0_i16, 1, 2, 3, 4, 5, 6, 7]))
1609            .build()
1610            .unwrap();
1611
1612        // Construct a buffer for value offsets, for the nested array:
1613        //  [[0, 1, 2], [3, 4, 5], [6, 7]]
1614        let value_offsets = Buffer::from(vec![0_i32, 3, 6]);
1615        let sizes_buffer = Buffer::from(vec![3_i32, 3, 2]);
1616
1617        // Construct a list array from the above two
1618        let list_view_dt =
1619            DataType::ListView(Arc::new(Field::new_list_field(DataType::Int16, false)));
1620
1621        let list_view_data = ArrayData::builder(list_view_dt)
1622            .len(3)
1623            .add_buffer(value_offsets)
1624            .add_buffer(sizes_buffer)
1625            .add_child_data(value_data)
1626            .build()
1627            .unwrap();
1628
1629        test_round_trip(&list_view_data)
1630    }
1631
1632    #[test]
1633    fn test_list_view_with_nulls() -> Result<()> {
1634        // Construct a value array
1635        let value_data = ArrayData::builder(DataType::Int16)
1636            .len(8)
1637            .add_buffer(Buffer::from_slice_ref([0_i16, 1, 2, 3, 4, 5, 6, 7]))
1638            .build()
1639            .unwrap();
1640
1641        // Construct a buffer for value offsets, for the nested array:
1642        //  [[0, 1, 2], [3, 4, 5], [6, 7], null]
1643        let value_offsets = Buffer::from(vec![0_i32, 3, 6, 8]);
1644        let sizes_buffer = Buffer::from(vec![3_i32, 3, 2, 0]);
1645
1646        // Construct a list array from the above two
1647        let list_view_dt =
1648            DataType::ListView(Arc::new(Field::new_list_field(DataType::Int16, true)));
1649
1650        let list_view_data = ArrayData::builder(list_view_dt)
1651            .len(4)
1652            .add_buffer(value_offsets)
1653            .add_buffer(sizes_buffer)
1654            .add_child_data(value_data)
1655            .nulls(Some(NullBuffer::from(vec![true, true, true, false])))
1656            .build()
1657            .unwrap();
1658
1659        test_round_trip(&list_view_data)
1660    }
1661
1662    #[test]
1663    #[cfg(not(feature = "force_validate"))]
1664    fn test_empty_string_with_non_zero_offset() -> Result<()> {
1665        use super::ImportedArrowArray;
1666        use arrow_buffer::{MutableBuffer, OffsetBuffer};
1667
1668        // Simulate an empty string array with a non-zero offset from a producer
1669        let data: Buffer = MutableBuffer::new(0).into();
1670        let offsets = OffsetBuffer::new(vec![123].into());
1671        let string_array =
1672            unsafe { StringArray::new_unchecked(offsets.clone(), data.clone(), None) };
1673
1674        let data = string_array.into_data();
1675
1676        let array = FFI_ArrowArray::new(&data);
1677        let schema = FFI_ArrowSchema::try_from(data.data_type())?;
1678
1679        let dt = DataType::try_from(&schema)?;
1680        let array = Arc::new(array);
1681        let imported_array = ImportedArrowArray {
1682            array: &array,
1683            data_type: dt,
1684            owner: &array,
1685        };
1686
1687        let offset_buf_len = imported_array.buffer_len(1, &[], &imported_array.data_type)?;
1688        let data_buf_len = imported_array.buffer_len(2, &[], &imported_array.data_type)?;
1689
1690        assert_eq!(offset_buf_len, 4);
1691        assert_eq!(data_buf_len, 0);
1692
1693        test_round_trip(&imported_array.consume()?)
1694    }
1695
1696    /// A zero-length `Utf8` / `Binary` array at a non-zero offset must survive a
1697    /// round trip: the length of the values buffer has to come from the last offset
1698    /// of the window, as it already does for non-empty arrays, rather than being
1699    /// short-circuited to 0 on the length alone.
1700    ///
1701    /// <https://github.com/apache/arrow-rs/issues/10910>
1702    #[test]
1703    fn test_zero_length_bytes_at_non_zero_offset() -> Result<()> {
1704        // "x", "aa", "bb", viewed as zero elements starting at `offset`.
1705        let small = Buffer::from_slice_ref([0i32, 1, 3, 5]);
1706        let large = Buffer::from_slice_ref([0i64, 1, 3, 5]);
1707        let values = Buffer::from(b"xaabb".as_slice());
1708
1709        for (data_type, offsets) in [
1710            (DataType::Utf8, &small),
1711            (DataType::Binary, &small),
1712            (DataType::LargeUtf8, &large),
1713            (DataType::LargeBinary, &large),
1714        ] {
1715            for offset in 0..4 {
1716                let data = ArrayData::try_new(
1717                    data_type.clone(),
1718                    0,
1719                    None,
1720                    offset,
1721                    vec![offsets.clone(), values.clone()],
1722                    vec![],
1723                )?;
1724
1725                let array = FFI_ArrowArray::new(&data);
1726                let schema = FFI_ArrowSchema::try_from(&data_type)?;
1727                let imported = unsafe { from_ffi(array, &schema) }?;
1728
1729                // `from_ffi` builds the `ArrayData` with `new_unchecked`, so an
1730                // inconsistency only surfaces once something validates it.
1731                imported.validate_full()?;
1732                assert_eq!(imported.len(), 0);
1733                assert_eq!(imported, data);
1734
1735                // The values buffer is sized from the last offset of the window,
1736                // not short-circuited to 0.
1737                assert_eq!(imported.buffers()[1].len(), [0, 1, 3, 5][offset]);
1738            }
1739        }
1740
1741        Ok(())
1742    }
1743
1744    fn roundtrip_string_array(array: StringArray) -> StringArray {
1745        let data = array.into_data();
1746
1747        let array = FFI_ArrowArray::new(&data);
1748        let schema = FFI_ArrowSchema::try_from(data.data_type()).unwrap();
1749
1750        let array = unsafe { from_ffi(array, &schema) }.unwrap();
1751        StringArray::from(array)
1752    }
1753
1754    fn roundtrip_byte_view_array<T: ByteViewType>(
1755        array: GenericByteViewArray<T>,
1756    ) -> GenericByteViewArray<T> {
1757        let data = array.into_data();
1758
1759        let array = FFI_ArrowArray::new(&data);
1760        let schema = FFI_ArrowSchema::try_from(data.data_type()).unwrap();
1761
1762        let array = unsafe { from_ffi(array, &schema) }.unwrap();
1763        GenericByteViewArray::<T>::from(array)
1764    }
1765
1766    fn extend_array(array: &dyn Array) -> ArrayRef {
1767        let len = array.len();
1768        let data = array.to_data();
1769
1770        let mut mutable = MutableArrayData::new(vec![&data], false, len);
1771        mutable.try_extend(0, 0, len).unwrap();
1772        make_array(mutable.freeze())
1773    }
1774
1775    #[test]
1776    fn test_extend_imported_string_slice() {
1777        let mut strings = vec![];
1778
1779        for i in 0..1000 {
1780            strings.push(format!("string: {i}"));
1781        }
1782
1783        let string_array = StringArray::from(strings);
1784
1785        let imported = roundtrip_string_array(string_array.clone());
1786        assert_eq!(imported.len(), 1000);
1787        assert_eq!(imported.value(0), "string: 0");
1788        assert_eq!(imported.value(499), "string: 499");
1789
1790        let copied = extend_array(&imported);
1791        assert_eq!(
1792            copied.as_any().downcast_ref::<StringArray>().unwrap(),
1793            &imported
1794        );
1795
1796        let slice = string_array.slice(500, 500);
1797
1798        let imported = roundtrip_string_array(slice);
1799        assert_eq!(imported.len(), 500);
1800        assert_eq!(imported.value(0), "string: 500");
1801        assert_eq!(imported.value(499), "string: 999");
1802
1803        let copied = extend_array(&imported);
1804        assert_eq!(
1805            copied.as_any().downcast_ref::<StringArray>().unwrap(),
1806            &imported
1807        );
1808    }
1809
1810    fn roundtrip_list_array(array: ListArray) -> ListArray {
1811        let data = array.into_data();
1812
1813        let array = FFI_ArrowArray::new(&data);
1814        let schema = FFI_ArrowSchema::try_from(data.data_type()).unwrap();
1815
1816        let array = unsafe { from_ffi(array, &schema) }.unwrap();
1817        ListArray::from(array)
1818    }
1819
1820    #[test]
1821    fn test_extend_imported_list_slice() {
1822        let mut data = vec![];
1823
1824        for i in 0..1000 {
1825            let mut list = vec![];
1826            for j in 0..100 {
1827                list.push(Some(i * 1000 + j));
1828            }
1829            data.push(Some(list));
1830        }
1831
1832        let list_array = ListArray::from_iter_primitive::<Int32Type, _, _>(data);
1833
1834        let slice = list_array.slice(500, 500);
1835        let imported = roundtrip_list_array(slice.clone());
1836        assert_eq!(imported.len(), 500);
1837        assert_eq!(&slice, &imported);
1838
1839        let copied = extend_array(&imported);
1840        assert_eq!(
1841            copied.as_any().downcast_ref::<ListArray>().unwrap(),
1842            &imported
1843        );
1844    }
1845
1846    /// Helper trait to allow us to use easily strings as either BinaryViewType::Native or
1847    /// StringViewType::Native scalars.
1848    trait NativeFromStr {
1849        fn from_str(value: &str) -> &Self;
1850    }
1851
1852    impl NativeFromStr for str {
1853        fn from_str(value: &str) -> &Self {
1854            value
1855        }
1856    }
1857
1858    impl NativeFromStr for [u8] {
1859        fn from_str(value: &str) -> &Self {
1860            value.as_bytes()
1861        }
1862    }
1863
1864    #[test]
1865    #[cfg(not(feature = "force_validate"))]
1866    fn test_utf8_view_ffi_from_dangling_pointer() {
1867        let empty = GenericByteViewBuilder::<StringViewType>::new().finish();
1868        let buffers = Arc::clone(empty.data_buffers());
1869        let nulls = empty.nulls().cloned();
1870
1871        // Create a dangling pointer to a view buffer with zero length.
1872        let alloc = Arc::new(1);
1873        let buffer = unsafe { Buffer::from_custom_allocation(NonNull::<u8>::dangling(), 0, alloc) };
1874        let views = unsafe { ScalarBuffer::new_unchecked(buffer) };
1875
1876        let str_view: GenericByteViewArray<StringViewType> =
1877            unsafe { GenericByteViewArray::new_unchecked(views, buffers, nulls) };
1878        let imported = roundtrip_byte_view_array(str_view);
1879        assert_eq!(imported.len(), 0);
1880        assert_eq!(&imported, &empty);
1881    }
1882
1883    #[test]
1884    fn test_round_trip_byte_view() {
1885        fn test_case<T>()
1886        where
1887            T: ByteViewType,
1888            T::Native: NativeFromStr,
1889        {
1890            macro_rules! run_test_case {
1891                ($array:expr) => {{
1892                    // round-trip through C  Data Interface
1893                    let len = $array.len();
1894                    let imported = roundtrip_byte_view_array($array);
1895                    assert_eq!(imported.len(), len);
1896
1897                    let copied = extend_array(&imported);
1898                    assert_eq!(
1899                        copied
1900                            .as_any()
1901                            .downcast_ref::<GenericByteViewArray<T>>()
1902                            .unwrap(),
1903                        &imported
1904                    );
1905                }};
1906            }
1907
1908            // Empty test case.
1909            let empty = GenericByteViewBuilder::<T>::new().finish();
1910            run_test_case!(empty);
1911
1912            // All inlined strings test case.
1913            let mut all_inlined = GenericByteViewBuilder::<T>::new();
1914            all_inlined.append_value(T::Native::from_str("inlined1"));
1915            all_inlined.append_value(T::Native::from_str("inlined2"));
1916            all_inlined.append_value(T::Native::from_str("inlined3"));
1917            let all_inlined = all_inlined.finish();
1918            assert_eq!(all_inlined.data_buffers().len(), 0);
1919            run_test_case!(all_inlined);
1920
1921            // some inlined + non-inlined, 1 variadic buffer.
1922            let mixed_one_variadic = {
1923                let mut builder = GenericByteViewBuilder::<T>::new();
1924                builder.append_value(T::Native::from_str("inlined"));
1925                let block_id = builder.append_block(Buffer::from(b"non-inlined-string-buffer"));
1926                builder.try_append_view(block_id, 0, 25).unwrap();
1927                builder.finish()
1928            };
1929            assert_eq!(mixed_one_variadic.data_buffers().len(), 1);
1930            run_test_case!(mixed_one_variadic);
1931
1932            // inlined + non-inlined, 2 variadic buffers.
1933            let mixed_two_variadic = {
1934                let mut builder = GenericByteViewBuilder::<T>::new();
1935                builder.append_value(T::Native::from_str("inlined"));
1936                let block_id = builder.append_block(Buffer::from(b"non-inlined-string-buffer"));
1937                builder.try_append_view(block_id, 0, 25).unwrap();
1938
1939                let block_id = builder
1940                    .append_block(Buffer::from("another-non-inlined-string-buffer".as_bytes()));
1941                builder.try_append_view(block_id, 0, 33).unwrap();
1942                builder.finish()
1943            };
1944            assert_eq!(mixed_two_variadic.data_buffers().len(), 2);
1945            run_test_case!(mixed_two_variadic);
1946        }
1947
1948        test_case::<StringViewType>();
1949        test_case::<BinaryViewType>();
1950    }
1951}