1use crate::bit_mask::set_bits;
21use crate::{ArrayData, layout};
22use arrow_buffer::buffer::NullBuffer;
23use arrow_buffer::{Buffer, MutableBuffer, ScalarBuffer};
24use arrow_schema::DataType;
25use std::ffi::c_void;
26
27#[repr(C)]
38#[derive(Debug)]
39pub struct FFI_ArrowArray {
40    length: i64,
41    null_count: i64,
42    offset: i64,
43    n_buffers: i64,
44    n_children: i64,
45    buffers: *mut *const c_void,
46    children: *mut *mut FFI_ArrowArray,
47    dictionary: *mut FFI_ArrowArray,
48    release: Option<unsafe extern "C" fn(arg1: *mut FFI_ArrowArray)>,
49    private_data: *mut c_void,
55}
56
57impl Drop for FFI_ArrowArray {
58    fn drop(&mut self) {
59        match self.release {
60            None => (),
61            Some(release) => unsafe { release(self) },
62        };
63    }
64}
65
66unsafe impl Send for FFI_ArrowArray {}
67unsafe impl Sync for FFI_ArrowArray {}
68
69unsafe extern "C" fn release_array(array: *mut FFI_ArrowArray) {
71    if array.is_null() {
72        return;
73    }
74    let array = unsafe { &mut *array };
75
76    let private = unsafe { Box::from_raw(array.private_data as *mut ArrayPrivateData) };
78    for child in private.children.iter() {
79        let _ = unsafe { Box::from_raw(*child) };
80    }
81    if !private.dictionary.is_null() {
82        let _ = unsafe { Box::from_raw(private.dictionary) };
83    }
84
85    array.release = None;
86}
87
88fn align_nulls(data_offset: usize, nulls: Option<&NullBuffer>) -> Option<Buffer> {
92    let nulls = nulls?;
93    if data_offset == nulls.offset() {
94        return Some(nulls.buffer().clone());
96    }
97    if data_offset == 0 {
98        return Some(nulls.inner().sliced());
99    }
100    let mut builder = MutableBuffer::new_null(data_offset + nulls.len());
101    set_bits(
102        builder.as_slice_mut(),
103        nulls.validity(),
104        data_offset,
105        nulls.offset(),
106        nulls.len(),
107    );
108    Some(builder.into())
109}
110
111struct ArrayPrivateData {
112    #[allow(dead_code)]
113    buffers: Vec<Option<Buffer>>,
114    buffers_ptr: Box<[*const c_void]>,
115    children: Box<[*mut FFI_ArrowArray]>,
116    dictionary: *mut FFI_ArrowArray,
117}
118
119impl FFI_ArrowArray {
120    pub fn new(data: &ArrayData) -> Self {
122        let data_layout = layout(data.data_type());
123
124        let mut buffers = if data_layout.can_contain_null_mask {
125            std::iter::once(align_nulls(data.offset(), data.nulls()))
128                .chain(data.buffers().iter().map(|b| Some(b.clone())))
129                .collect::<Vec<_>>()
130        } else {
131            data.buffers().iter().map(|b| Some(b.clone())).collect()
132        };
133
134        let mut n_buffers = {
136            data_layout.buffers.len() + {
137                usize::from(data_layout.can_contain_null_mask)
141            }
142        } as i64;
143
144        if data_layout.variadic {
145            let mut data_buffers_lengths = Vec::new();
148            for buffer in data.buffers().iter().skip(1) {
149                data_buffers_lengths.push(buffer.len() as i64);
150                n_buffers += 1;
151            }
152
153            buffers.push(Some(ScalarBuffer::from(data_buffers_lengths).into_inner()));
154            n_buffers += 1;
155        }
156
157        let buffers_ptr = buffers
158            .iter()
159            .flat_map(|maybe_buffer| match maybe_buffer {
160                Some(b) => Some(b.as_ptr() as *const c_void),
161                None if data_layout.can_contain_null_mask => Some(std::ptr::null()),
164                None => None,
165            })
166            .collect::<Box<[_]>>();
167
168        let empty = vec![];
169        let (child_data, dictionary) = match data.data_type() {
170            DataType::Dictionary(_, _) => (
171                empty.as_slice(),
172                Box::into_raw(Box::new(FFI_ArrowArray::new(&data.child_data()[0]))),
173            ),
174            _ => (data.child_data(), std::ptr::null_mut()),
175        };
176
177        let children = child_data
178            .iter()
179            .map(|child| Box::into_raw(Box::new(FFI_ArrowArray::new(child))))
180            .collect::<Box<_>>();
181        let n_children = children.len() as i64;
182
183        let null_count = match data.data_type() {
185            DataType::Null => data.len(),
186            _ => data.null_count(),
187        };
188
189        let mut private_data = Box::new(ArrayPrivateData {
192            buffers,
193            buffers_ptr,
194            children,
195            dictionary,
196        });
197
198        Self {
199            length: data.len() as i64,
200            null_count: null_count as i64,
201            offset: data.offset() as i64,
202            n_buffers,
203            n_children,
204            buffers: private_data.buffers_ptr.as_mut_ptr(),
205            children: private_data.children.as_mut_ptr(),
206            dictionary,
207            release: Some(release_array),
208            private_data: Box::into_raw(private_data) as *mut c_void,
209        }
210    }
211
212    pub unsafe fn from_raw(array: *mut FFI_ArrowArray) -> Self {
225        unsafe { std::ptr::replace(array, Self::empty()) }
226    }
227
228    pub fn empty() -> Self {
230        Self {
231            length: 0,
232            null_count: 0,
233            offset: 0,
234            n_buffers: 0,
235            n_children: 0,
236            buffers: std::ptr::null_mut(),
237            children: std::ptr::null_mut(),
238            dictionary: std::ptr::null_mut(),
239            release: None,
240            private_data: std::ptr::null_mut(),
241        }
242    }
243
244    #[inline]
246    pub fn len(&self) -> usize {
247        self.length as usize
248    }
249
250    #[inline]
252    pub fn is_empty(&self) -> bool {
253        self.length == 0
254    }
255
256    #[inline]
258    pub fn is_released(&self) -> bool {
259        self.release.is_none()
260    }
261
262    #[inline]
264    pub fn offset(&self) -> usize {
265        self.offset as usize
266    }
267
268    #[inline]
270    pub fn null_count(&self) -> usize {
271        self.null_count as usize
272    }
273
274    #[inline]
276    pub fn null_count_opt(&self) -> Option<usize> {
277        usize::try_from(self.null_count).ok()
278    }
279
280    #[inline]
285    pub unsafe fn set_null_count(&mut self, null_count: i64) {
286        self.null_count = null_count;
287    }
288
289    #[inline]
294    pub fn buffer(&self, index: usize) -> *const u8 {
295        assert!(!self.buffers.is_null());
296        assert!(index < self.num_buffers());
297        unsafe { std::ptr::read_unaligned((self.buffers as *mut *const u8).add(index)) }
300    }
301
302    #[inline]
304    pub fn num_buffers(&self) -> usize {
305        self.n_buffers as _
306    }
307
308    #[inline]
310    pub fn child(&self, index: usize) -> &FFI_ArrowArray {
311        assert!(!self.children.is_null());
312        assert!(index < self.num_children());
313        unsafe {
316            let child = std::ptr::read_unaligned(self.children.add(index));
317            child.as_ref().unwrap()
318        }
319    }
320
321    #[inline]
323    pub fn num_children(&self) -> usize {
324        self.n_children as _
325    }
326
327    #[inline]
329    pub fn dictionary(&self) -> Option<&Self> {
330        unsafe { self.dictionary.as_ref() }
333    }
334}
335
336#[cfg(test)]
337mod tests {
338    use super::*;
339
340    #[test]
343    fn null_array_n_buffers() {
344        let data = ArrayData::new_null(&DataType::Null, 10);
345
346        let ffi_array = FFI_ArrowArray::new(&data);
347        assert_eq!(0, ffi_array.n_buffers);
348
349        let private_data =
350            unsafe { Box::from_raw(ffi_array.private_data as *mut ArrayPrivateData) };
351
352        assert_eq!(0, private_data.buffers_ptr.len());
353
354        let _ = Box::into_raw(private_data);
355    }
356}