use std::ffi::c_void;
use std::marker::PhantomData;
use arrow::array::{RecordBatch, StructArray};
use arrow::datatypes::SchemaRef;
use arrow::error::ArrowError;
use arrow::ffi::{from_ffi, FFI_ArrowArray, FFI_ArrowSchema};
use arrow::ffi_stream::{ArrowArrayStreamReader, FFI_ArrowArrayStream};
use arrow::record_batch::RecordBatchReader;
use crate::workbook::{build_specs, check, ExcelMapper, Workbook};
use crate::{Error, XL_ERROR};
pub fn parse_arrow<T: ExcelMapper>(
workbook: &mut Workbook,
header_row: i32,
) -> Result<RecordBatch, Error> {
let arena = build_specs::<T>();
let mut array = FFI_ArrowArray::empty();
let mut schema = FFI_ArrowSchema::empty();
check(unsafe {
crate::xl_parse_arrow(
workbook.handle(),
arena.specs.as_ptr(),
arena.specs.len() as i32,
header_row,
&mut array as *mut FFI_ArrowArray as *mut c_void,
&mut schema as *mut FFI_ArrowSchema as *mut c_void,
)
})?;
let data = unsafe { from_ffi(array, &schema) }.map_err(|e| {
Error::from_status(
XL_ERROR,
format!("importing the native Arrow array failed: {e}"),
)
})?;
Ok(RecordBatch::from(StructArray::from(data)))
}
pub struct ArrowChunks<'a> {
inner: ArrowArrayStreamReader,
_workbook: PhantomData<&'a mut Workbook>,
}
impl Iterator for ArrowChunks<'_> {
type Item = Result<RecordBatch, ArrowError>;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
impl RecordBatchReader for ArrowChunks<'_> {
fn schema(&self) -> SchemaRef {
self.inner.schema()
}
}
pub fn parse_arrow_stream<T: ExcelMapper>(
workbook: &mut Workbook,
header_row: i32,
batch_size: i64,
) -> Result<ArrowChunks<'_>, Error> {
let arena = build_specs::<T>();
let mut stream = FFI_ArrowArrayStream::empty();
check(unsafe {
crate::xl_parse_arrow_stream(
workbook.handle(),
arena.specs.as_ptr(),
arena.specs.len() as i32,
header_row,
batch_size,
&mut stream as *mut FFI_ArrowArrayStream as *mut c_void,
)
})?;
let inner = ArrowArrayStreamReader::try_new(stream).map_err(|e| {
Error::from_status(
XL_ERROR,
format!("importing the native Arrow stream failed: {e}"),
)
})?;
Ok(ArrowChunks {
inner,
_workbook: PhantomData,
})
}