From fa2ec44733c228573f0659a107bafcf932ff3f30 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Tue, 15 Mar 2022 20:07:49 -0700 Subject: [PATCH 1/9] Remove Clone and copy source structs internally --- arrow/src/ffi.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 461995bdbaf9..0bf052b2dd52 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -107,7 +107,7 @@ bitflags! { /// See /// This was created by bindgen #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FFI_ArrowSchema { format: *const c_char, name: *const c_char, @@ -336,7 +336,7 @@ fn bit_width(data_type: &DataType, i: usize) -> Result { /// See /// This was created by bindgen #[repr(C)] -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FFI_ArrowArray { pub(crate) length: i64, pub(crate) null_count: i64, @@ -781,11 +781,19 @@ impl ArrowArray { .to_string(), )); }; - let ffi_array = (*array).clone(); - let ffi_schema = (*schema).clone(); + + let array_mut = array as *mut FFI_ArrowArray; + let schema_mut = schema as *mut FFI_ArrowSchema; + + let array_data = std::ptr::replace(array_mut, FFI_ArrowArray::empty()); + let schema_data = std::ptr::replace(schema_mut, FFI_ArrowSchema::empty()); + + std::ptr::drop_in_place(array_mut); + std::ptr::drop_in_place(schema_mut); + Ok(Self { - array: Arc::new(ffi_array), - schema: Arc::new(ffi_schema), + array: Arc::new(array_data), + schema: Arc::new(schema_data), }) } From 44bafd3ceab247654675a7ed9ccaabc83aa00b6d Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Tue, 15 Mar 2022 23:13:41 -0700 Subject: [PATCH 2/9] Remove drop_in_place and add more comment --- arrow/src/ffi.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 0bf052b2dd52..9d22e5c03e3f 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -769,6 +769,9 @@ impl ArrowArray { /// creates a new [ArrowArray] from two pointers. Used to import from the C Data Interface. /// # Safety /// See safety of [ArrowArray] + /// Note that this function will copy the content pointed by the raw pointers. Considering + /// the raw pointers can be from `Arc::into_raw` or other raw pointers, users must be responsible + /// on managing the allocation of the structs by themselves. /// # Error /// Errors if any of the pointers is null pub unsafe fn try_from_raw( @@ -788,9 +791,6 @@ impl ArrowArray { let array_data = std::ptr::replace(array_mut, FFI_ArrowArray::empty()); let schema_data = std::ptr::replace(schema_mut, FFI_ArrowSchema::empty()); - std::ptr::drop_in_place(array_mut); - std::ptr::drop_in_place(schema_mut); - Ok(Self { array: Arc::new(array_data), schema: Arc::new(schema_data), From 0705d337a9708d490a100ef206d68f553d83fbfb Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 00:24:12 -0700 Subject: [PATCH 3/9] Add export_into_raw --- arrow/src/ffi.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 9d22e5c03e3f..2ded97e052b2 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -810,6 +810,33 @@ impl ArrowArray { pub fn into_raw(this: ArrowArray) -> (*const FFI_ArrowArray, *const FFI_ArrowSchema) { (Arc::into_raw(this.array), Arc::into_raw(this.schema)) } + + /// exports [ArrowArray] to raw pointers of the C Data Interface provided by the consumer. + /// # Safety + /// See safety of [ArrowArray] + /// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in + /// this [ArrowArray] to the location pointed by the raw pointers. Usually the raw pointers are + /// provided by the array data consumer. + pub fn export_into_raw(this: ArrowArray, out_array: *mut FFI_ArrowArray, out_schema: *mut FFI_ArrowSchema) { + let array = Arc::into_raw(this.array); + let schema = Arc::into_raw(this.schema); + unsafe { + std::ptr::copy_nonoverlapping(array, out_array, 1); + std::ptr::copy_nonoverlapping(schema, out_schema, 1); + + // Clean up the structs to avoid double-dropping + let empty_array = Box::into_raw(Box::new(FFI_ArrowArray::empty())); + let empty_schema = Box::into_raw(Box::new(FFI_ArrowSchema::empty())); + std::ptr::copy_nonoverlapping(empty_array, array as *mut FFI_ArrowArray, 1); + std::ptr::copy_nonoverlapping(empty_schema, schema as *mut FFI_ArrowSchema, 1); + + // Drop Box and Arc pointers + Box::from_raw(empty_array); + Box::from_raw(empty_schema); + Arc::from_raw(array); + Arc::from_raw(schema); + } + } } impl<'a> ArrowArrayChild<'a> { @@ -1172,4 +1199,36 @@ mod tests { // (drop/release) Ok(()) } + + #[test] + fn test_export_into_raw() -> Result<()> { + let array = Int32Array::from(vec![1, 2, 3]); + let arrow_array = ArrowArray::try_from(array.data().clone())?; + + // Assume two raw pointers provided by the consumer + let out_array = Box::new(FFI_ArrowArray::empty()); + let out_schema = Box::new(FFI_ArrowSchema::empty()); + let out_array_ptr = Box::into_raw(out_array); + let out_schema_ptr = Box::into_raw(out_schema); + + ArrowArray::export_into_raw(arrow_array, out_array_ptr, out_schema_ptr); + + // (simulate consumer) import it + unsafe { + let array = ArrowArray::try_from_raw(out_array_ptr, out_schema_ptr).unwrap(); + let data = ArrayData::try_from(array)?; + let array = make_array(data); + + // perform some operation + let array = array.as_any().downcast_ref::().unwrap(); + let array = kernels::arithmetic::add(array, array).unwrap(); + + // verify + assert_eq!(array, Int32Array::from(vec![2, 4, 6])); + + Box::from_raw(out_array_ptr); + Box::from_raw(out_schema_ptr); + } + Ok(()) + } } From 27c075d5076d22c248c823208ca9f96491092b43 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 00:25:16 -0700 Subject: [PATCH 4/9] Fix format --- arrow/src/ffi.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 2ded97e052b2..1143b7c3e882 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -817,8 +817,12 @@ impl ArrowArray { /// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in /// this [ArrowArray] to the location pointed by the raw pointers. Usually the raw pointers are /// provided by the array data consumer. - pub fn export_into_raw(this: ArrowArray, out_array: *mut FFI_ArrowArray, out_schema: *mut FFI_ArrowSchema) { - let array = Arc::into_raw(this.array); + pub fn export_into_raw( + this: ArrowArray, + out_array: *mut FFI_ArrowArray, + out_schema: *mut FFI_ArrowSchema, + ) { + let array = Arc::into_raw(this.array); let schema = Arc::into_raw(this.schema); unsafe { std::ptr::copy_nonoverlapping(array, out_array, 1); @@ -828,7 +832,11 @@ impl ArrowArray { let empty_array = Box::into_raw(Box::new(FFI_ArrowArray::empty())); let empty_schema = Box::into_raw(Box::new(FFI_ArrowSchema::empty())); std::ptr::copy_nonoverlapping(empty_array, array as *mut FFI_ArrowArray, 1); - std::ptr::copy_nonoverlapping(empty_schema, schema as *mut FFI_ArrowSchema, 1); + std::ptr::copy_nonoverlapping( + empty_schema, + schema as *mut FFI_ArrowSchema, + 1, + ); // Drop Box and Arc pointers Box::from_raw(empty_array); From 29157dbddf9dd50f6c8366bed366374cf695b1e0 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 10:10:20 -0700 Subject: [PATCH 5/9] Fix clippy --- arrow/src/ffi.rs | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 1143b7c3e882..276b1d5f090c 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -817,33 +817,27 @@ impl ArrowArray { /// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in /// this [ArrowArray] to the location pointed by the raw pointers. Usually the raw pointers are /// provided by the array data consumer. - pub fn export_into_raw( + pub unsafe fn export_into_raw( this: ArrowArray, out_array: *mut FFI_ArrowArray, out_schema: *mut FFI_ArrowSchema, ) { let array = Arc::into_raw(this.array); let schema = Arc::into_raw(this.schema); - unsafe { - std::ptr::copy_nonoverlapping(array, out_array, 1); - std::ptr::copy_nonoverlapping(schema, out_schema, 1); - - // Clean up the structs to avoid double-dropping - let empty_array = Box::into_raw(Box::new(FFI_ArrowArray::empty())); - let empty_schema = Box::into_raw(Box::new(FFI_ArrowSchema::empty())); - std::ptr::copy_nonoverlapping(empty_array, array as *mut FFI_ArrowArray, 1); - std::ptr::copy_nonoverlapping( - empty_schema, - schema as *mut FFI_ArrowSchema, - 1, - ); - - // Drop Box and Arc pointers - Box::from_raw(empty_array); - Box::from_raw(empty_schema); - Arc::from_raw(array); - Arc::from_raw(schema); - } + std::ptr::copy_nonoverlapping(array, out_array, 1); + std::ptr::copy_nonoverlapping(schema, out_schema, 1); + + // Clean up the structs to avoid double-dropping + let empty_array = Box::into_raw(Box::new(FFI_ArrowArray::empty())); + let empty_schema = Box::into_raw(Box::new(FFI_ArrowSchema::empty())); + std::ptr::copy_nonoverlapping(empty_array, array as *mut FFI_ArrowArray, 1); + std::ptr::copy_nonoverlapping(empty_schema, schema as *mut FFI_ArrowSchema, 1); + + // Drop Box and Arc pointers + Box::from_raw(empty_array); + Box::from_raw(empty_schema); + Arc::from_raw(array); + Arc::from_raw(schema); } } @@ -1219,7 +1213,9 @@ mod tests { let out_array_ptr = Box::into_raw(out_array); let out_schema_ptr = Box::into_raw(out_schema); - ArrowArray::export_into_raw(arrow_array, out_array_ptr, out_schema_ptr); + unsafe { + ArrowArray::export_into_raw(arrow_array, out_array_ptr, out_schema_ptr); + } // (simulate consumer) import it unsafe { From ac804bcf7070fc9f83af088f7d5f85924944d5e9 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 11:29:01 -0700 Subject: [PATCH 6/9] Move to export_array_into_raw --- arrow/src/array/array.rs | 34 ++++++++++++++++++ arrow/src/array/mod.rs | 2 +- arrow/src/ffi.rs | 75 ++++++++++++++++++++-------------------- 3 files changed, 72 insertions(+), 39 deletions(-) diff --git a/arrow/src/array/array.rs b/arrow/src/array/array.rs index 795439ec80a5..0f8d97689cac 100644 --- a/arrow/src/array/array.rs +++ b/arrow/src/array/array.rs @@ -632,6 +632,40 @@ pub unsafe fn make_array_from_raw( let data = ArrayData::try_from(array)?; Ok(make_array(data)) } + +/// Exports an array to raw pointers of the C Data Interface provided by the consumer. +/// # Safety +/// Assumes that these pointers represent valid C Data Interfaces, both in memory +/// representation and lifetime via the `release` mechanism. +/// +/// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in +/// the array to the location pointed by the raw pointers. Usually the raw pointers are +/// provided by the array data consumer. +pub unsafe fn export_array_into_raw( + src: ArrayRef, + out_array: *mut ffi::FFI_ArrowArray, + out_schema: *mut ffi::FFI_ArrowSchema, +) -> Result<()> { + let (array, schema) = src.to_raw()?; + + std::ptr::copy_nonoverlapping(array, out_array, 1); + std::ptr::copy_nonoverlapping(schema, out_schema, 1); + + // Clean up the structs to avoid double-dropping + let empty_array = Box::into_raw(Box::new(ffi::FFI_ArrowArray::empty())); + let empty_schema = Box::into_raw(Box::new(ffi::FFI_ArrowSchema::empty())); + std::ptr::copy_nonoverlapping(empty_array, array as *mut ffi::FFI_ArrowArray, 1); + std::ptr::copy_nonoverlapping(empty_schema, schema as *mut ffi::FFI_ArrowSchema, 1); + + // Drop Box and Arc pointers + Box::from_raw(empty_array); + Box::from_raw(empty_schema); + Arc::from_raw(array); + Arc::from_raw(schema); + + Ok(()) +} + // Helper function for printing potentially long arrays. pub(super) fn print_long_array( array: &A, diff --git a/arrow/src/array/mod.rs b/arrow/src/array/mod.rs index 864bae1d8107..fc6441b24cc4 100644 --- a/arrow/src/array/mod.rs +++ b/arrow/src/array/mod.rs @@ -521,7 +521,7 @@ pub use self::cast::{ // ------------------------------ C Data Interface --------------------------- -pub use self::array::make_array_from_raw; +pub use self::array::{export_array_into_raw, make_array_from_raw}; #[cfg(test)] mod tests { diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 276b1d5f090c..77b9afed7bce 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -26,9 +26,10 @@ //! //! ```rust //! # use std::sync::Arc; -//! # use arrow::array::{Int32Array, Array, ArrayData, make_array_from_raw}; +//! # use arrow::array::{Int32Array, Array, ArrayData, export_array_into_raw, make_array, make_array_from_raw}; //! # use arrow::error::{Result, ArrowError}; //! # use arrow::compute::kernels::arithmetic; +//! # use arrow::ffi::{FFI_ArrowArray, FFI_ArrowSchema}; //! # use std::convert::TryFrom; //! # fn main() -> Result<()> { //! // create an array natively @@ -51,7 +52,35 @@ //! // verify //! assert_eq!(array, Int32Array::from(vec![Some(2), None, Some(6)])); //! +//! // Simulate if raw pointers are provided by consumer +//! let array = make_array(Int32Array::from(vec![Some(1), None, Some(3)]).data().clone()); +//! +//! let out_array = Box::new(FFI_ArrowArray::empty()); +//! let out_schema = Box::new(FFI_ArrowSchema::empty()); +//! let out_array_ptr = Box::into_raw(out_array); +//! let out_schema_ptr = Box::into_raw(out_schema); +//! +//! // export array into raw pointers from consumer +//! unsafe { export_array_into_raw(array, out_array_ptr, out_schema_ptr)?; }; +//! +//! // import it +//! let array = unsafe { make_array_from_raw(out_array_ptr, out_schema_ptr)? }; +//! +//! // perform some operation +//! let array = array.as_any().downcast_ref::().ok_or( +//! ArrowError::ParseError("Expects an int32".to_string()), +//! )?; +//! let array = arithmetic::add(&array, &array)?; +//! +//! // verify +//! assert_eq!(array, Int32Array::from(vec![Some(2), None, Some(6)])); +//! //! // (drop/release) +//! unsafe { +//! Box::from_raw(out_array_ptr); +//! Box::from_raw(out_schema_ptr); +//! } +//! //! Ok(()) //! } //! ``` @@ -810,35 +839,6 @@ impl ArrowArray { pub fn into_raw(this: ArrowArray) -> (*const FFI_ArrowArray, *const FFI_ArrowSchema) { (Arc::into_raw(this.array), Arc::into_raw(this.schema)) } - - /// exports [ArrowArray] to raw pointers of the C Data Interface provided by the consumer. - /// # Safety - /// See safety of [ArrowArray] - /// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in - /// this [ArrowArray] to the location pointed by the raw pointers. Usually the raw pointers are - /// provided by the array data consumer. - pub unsafe fn export_into_raw( - this: ArrowArray, - out_array: *mut FFI_ArrowArray, - out_schema: *mut FFI_ArrowSchema, - ) { - let array = Arc::into_raw(this.array); - let schema = Arc::into_raw(this.schema); - std::ptr::copy_nonoverlapping(array, out_array, 1); - std::ptr::copy_nonoverlapping(schema, out_schema, 1); - - // Clean up the structs to avoid double-dropping - let empty_array = Box::into_raw(Box::new(FFI_ArrowArray::empty())); - let empty_schema = Box::into_raw(Box::new(FFI_ArrowSchema::empty())); - std::ptr::copy_nonoverlapping(empty_array, array as *mut FFI_ArrowArray, 1); - std::ptr::copy_nonoverlapping(empty_schema, schema as *mut FFI_ArrowSchema, 1); - - // Drop Box and Arc pointers - Box::from_raw(empty_array); - Box::from_raw(empty_schema); - Arc::from_raw(array); - Arc::from_raw(schema); - } } impl<'a> ArrowArrayChild<'a> { @@ -859,10 +859,10 @@ impl<'a> ArrowArrayChild<'a> { mod tests { use super::*; use crate::array::{ - make_array, Array, ArrayData, BinaryOffsetSizeTrait, BooleanArray, DecimalArray, - DictionaryArray, GenericBinaryArray, GenericListArray, GenericStringArray, - Int32Array, OffsetSizeTrait, StringOffsetSizeTrait, Time32MillisecondArray, - TimestampMillisecondArray, + export_array_into_raw, make_array, Array, ArrayData, BinaryOffsetSizeTrait, + BooleanArray, DecimalArray, DictionaryArray, GenericBinaryArray, + GenericListArray, GenericStringArray, Int32Array, OffsetSizeTrait, + StringOffsetSizeTrait, Time32MillisecondArray, TimestampMillisecondArray, }; use crate::compute::kernels; use crate::datatypes::{Field, Int8Type}; @@ -1203,9 +1203,8 @@ mod tests { } #[test] - fn test_export_into_raw() -> Result<()> { - let array = Int32Array::from(vec![1, 2, 3]); - let arrow_array = ArrowArray::try_from(array.data().clone())?; + fn test_export_array_into_raw() -> Result<()> { + let array = make_array(Int32Array::from(vec![1, 2, 3]).data().clone()); // Assume two raw pointers provided by the consumer let out_array = Box::new(FFI_ArrowArray::empty()); @@ -1214,7 +1213,7 @@ mod tests { let out_schema_ptr = Box::into_raw(out_schema); unsafe { - ArrowArray::export_into_raw(arrow_array, out_array_ptr, out_schema_ptr); + export_array_into_raw(array, out_array_ptr, out_schema_ptr); } // (simulate consumer) import it From 3fc6fab29695f703888646ace59dc29e93c98fdf Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 12:01:13 -0700 Subject: [PATCH 7/9] Fix clippy --- arrow/src/ffi.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 77b9afed7bce..73617d998764 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -1213,7 +1213,7 @@ mod tests { let out_schema_ptr = Box::into_raw(out_schema); unsafe { - export_array_into_raw(array, out_array_ptr, out_schema_ptr); + export_array_into_raw(array, out_array_ptr, out_schema_ptr)?; } // (simulate consumer) import it From 888cbe0edcf590e1228980d005e73936a29f4b39 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 12:25:21 -0700 Subject: [PATCH 8/9] Fix doc --- arrow/src/array/array.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arrow/src/array/array.rs b/arrow/src/array/array.rs index 0f8d97689cac..4af1e6e16fbe 100644 --- a/arrow/src/array/array.rs +++ b/arrow/src/array/array.rs @@ -638,9 +638,9 @@ pub unsafe fn make_array_from_raw( /// Assumes that these pointers represent valid C Data Interfaces, both in memory /// representation and lifetime via the `release` mechanism. /// -/// This function copies the content of two FFI structs [FFI_ArrowArray] and [FFI_ArrowSchema] in -/// the array to the location pointed by the raw pointers. Usually the raw pointers are -/// provided by the array data consumer. +/// This function copies the content of two FFI structs [ffi::FFI_ArrowArray] and +/// [ffi::FFI_ArrowSchema] in the array to the location pointed by the raw pointers. +/// Usually the raw pointers are provided by the array data consumer. pub unsafe fn export_array_into_raw( src: ArrayRef, out_array: *mut ffi::FFI_ArrowArray, From 6007aed4f6a66caa2e383155df821f0cd3e70189 Mon Sep 17 00:00:00 2001 From: Liang-Chi Hsieh Date: Fri, 18 Mar 2022 15:10:29 -0700 Subject: [PATCH 9/9] Use write_unaligned --- arrow/src/array/array.rs | 22 ++++++---------------- arrow/src/ffi.rs | 2 +- 2 files changed, 7 insertions(+), 17 deletions(-) diff --git a/arrow/src/array/array.rs b/arrow/src/array/array.rs index 4af1e6e16fbe..1ad01f4f0d4b 100644 --- a/arrow/src/array/array.rs +++ b/arrow/src/array/array.rs @@ -646,22 +646,12 @@ pub unsafe fn export_array_into_raw( out_array: *mut ffi::FFI_ArrowArray, out_schema: *mut ffi::FFI_ArrowSchema, ) -> Result<()> { - let (array, schema) = src.to_raw()?; - - std::ptr::copy_nonoverlapping(array, out_array, 1); - std::ptr::copy_nonoverlapping(schema, out_schema, 1); - - // Clean up the structs to avoid double-dropping - let empty_array = Box::into_raw(Box::new(ffi::FFI_ArrowArray::empty())); - let empty_schema = Box::into_raw(Box::new(ffi::FFI_ArrowSchema::empty())); - std::ptr::copy_nonoverlapping(empty_array, array as *mut ffi::FFI_ArrowArray, 1); - std::ptr::copy_nonoverlapping(empty_schema, schema as *mut ffi::FFI_ArrowSchema, 1); - - // Drop Box and Arc pointers - Box::from_raw(empty_array); - Box::from_raw(empty_schema); - Arc::from_raw(array); - Arc::from_raw(schema); + let data = src.data(); + let array = ffi::FFI_ArrowArray::new(data); + let schema = ffi::FFI_ArrowSchema::try_from(data.data_type())?; + + std::ptr::write_unaligned(out_array, array); + std::ptr::write_unaligned(out_schema, schema); Ok(()) } diff --git a/arrow/src/ffi.rs b/arrow/src/ffi.rs index 73617d998764..5fb1cce4eb57 100644 --- a/arrow/src/ffi.rs +++ b/arrow/src/ffi.rs @@ -425,7 +425,7 @@ impl FFI_ArrowArray { /// # Safety /// This method releases `buffers`. Consumers of this struct *must* call `release` before /// releasing this struct, or contents in `buffers` leak. - fn new(data: &ArrayData) -> Self { + pub(crate) fn new(data: &ArrayData) -> Self { // * insert the null buffer at the start // * make all others `Option`. let buffers = iter::once(data.null_buffer().cloned())