Skip to main content

libduckdb_sys/
arrow_c_data.rs

1//! Arrow C Data Interface layouts used by DuckDB's Arrow conversion APIs.
2//!
3//! DuckDB's public C header forward-declares these structs. The conversion
4//! APIs need concrete caller-allocated layouts, so `libduckdb-sys` defines the
5//! ABI records directly without taking a dependency on arrow-rs.
6//!
7//! Specification: <https://arrow.apache.org/docs/format/CDataInterface.html>
8
9use std::{
10    ffi::{c_char, c_void},
11    ptr,
12};
13
14/// Arrow C Data Interface array.
15#[repr(C)]
16#[derive(Debug)]
17pub struct ArrowArray {
18    pub length: i64,
19    pub null_count: i64,
20    pub offset: i64,
21    pub n_buffers: i64,
22    pub n_children: i64,
23    pub buffers: *mut *const c_void,
24    pub children: *mut *mut ArrowArray,
25    pub dictionary: *mut ArrowArray,
26    pub release: Option<unsafe extern "C" fn(*mut ArrowArray)>,
27    pub private_data: *mut c_void,
28}
29
30impl ArrowArray {
31    /// Creates a null-release placeholder for a producer to fill.
32    pub const fn empty() -> Self {
33        Self {
34            length: 0,
35            null_count: 0,
36            offset: 0,
37            n_buffers: 0,
38            n_children: 0,
39            buffers: ptr::null_mut(),
40            children: ptr::null_mut(),
41            dictionary: ptr::null_mut(),
42            release: None,
43            private_data: ptr::null_mut(),
44        }
45    }
46}
47
48/// Arrow C Data Interface schema.
49#[repr(C)]
50#[derive(Debug)]
51pub struct ArrowSchema {
52    pub format: *const c_char,
53    pub name: *const c_char,
54    pub metadata: *const c_char,
55    pub flags: i64,
56    pub n_children: i64,
57    pub children: *mut *mut ArrowSchema,
58    pub dictionary: *mut ArrowSchema,
59    pub release: Option<unsafe extern "C" fn(*mut ArrowSchema)>,
60    pub private_data: *mut c_void,
61}
62
63impl ArrowSchema {
64    /// Creates a null-release placeholder for a producer to fill.
65    pub const fn empty() -> Self {
66        Self {
67            format: ptr::null(),
68            name: ptr::null(),
69            metadata: ptr::null(),
70            flags: 0,
71            n_children: 0,
72            children: ptr::null_mut(),
73            dictionary: ptr::null_mut(),
74            release: None,
75            private_data: ptr::null_mut(),
76        }
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use std::mem::{align_of, offset_of, size_of};
84
85    use arrow::ffi::{FFI_ArrowArray, FFI_ArrowSchema};
86
87    macro_rules! assert_offsets {
88        ($left:ty, $right:ty, $($field:ident),+ $(,)?) => {
89            $(
90                assert_eq!(
91                    offset_of!($left, $field),
92                    offset_of!($right, $field),
93                    concat!("field offset differs for ", stringify!($field))
94                );
95            )+
96        };
97    }
98
99    #[test]
100    fn matches_arrow_rs_layouts() {
101        assert_eq!(size_of::<ArrowArray>(), size_of::<FFI_ArrowArray>());
102        assert_eq!(align_of::<ArrowArray>(), align_of::<FFI_ArrowArray>());
103        assert_offsets!(
104            ArrowArray,
105            FFI_ArrowArray,
106            length,
107            null_count,
108            offset,
109            n_buffers,
110            n_children,
111            buffers,
112            children,
113            dictionary,
114            release,
115            private_data,
116        );
117
118        assert_eq!(size_of::<ArrowSchema>(), size_of::<FFI_ArrowSchema>());
119        assert_eq!(align_of::<ArrowSchema>(), align_of::<FFI_ArrowSchema>());
120        assert_offsets!(
121            ArrowSchema,
122            FFI_ArrowSchema,
123            format,
124            name,
125            metadata,
126            flags,
127            n_children,
128            children,
129            dictionary,
130            release,
131            private_data,
132        );
133    }
134}