1use minarrow::ffi::arrow_dtype::ArrowType;
71use minarrow::{Array, Field, FieldArray, FloatArray, IntegerArray, MaskedArray, NumericArray, Table};
72use minarrow_pyo3::ffi::{to_py, to_rust};
73use pyo3::prelude::*;
74use pyo3::types::IntoPyDict;
75use std::sync::Arc;
76
77fn main() -> PyResult<()> {
78 pyo3::prepare_freethreaded_python();
79
80 Python::with_gil(|py| {
81 println!("=== Arrow PyCapsule Interface Examples ===\n");
82
83 example_1_export_array(py)?;
84 example_2_export_table_stream(py)?;
85 example_3_import_from_pyarrow_array(py)?;
86 example_4_import_from_pyarrow_table(py)?;
87
88 println!("\n=== All examples completed ===");
89 Ok(())
90 })
91}
92
93fn example_1_export_array(py: Python<'_>) -> PyResult<()> {
98 println!("Example 1: Export MinArrow array -> PyArrow via __arrow_c_array__");
99 println!("----------------------------------------------------------------");
100
101 let mut arr = IntegerArray::<i64>::default();
103 for i in 0..5 {
104 arr.push(i * 10);
105 }
106 let array = Array::from_int64(arr);
107 let field = Field::new("values", ArrowType::Int64, false, None);
108 println!(" Created MinArrow i64 array: [0, 10, 20, 30, 40]");
109
110 let (schema_capsule, array_capsule) =
112 to_py::array_to_capsules(Arc::new(array), &field, py)?;
113 println!(" Exported as PyCapsules");
114
115 let pyarrow = py.import("pyarrow")?;
119
120 let array_ptr = unsafe {
123 pyo3::ffi::PyCapsule_GetPointer(
124 array_capsule.as_ptr(),
125 c"arrow_array".as_ptr(),
126 )
127 } as usize;
128 let schema_ptr = unsafe {
129 pyo3::ffi::PyCapsule_GetPointer(
130 schema_capsule.as_ptr(),
131 c"arrow_schema".as_ptr(),
132 )
133 } as usize;
134
135 let pa_array = pyarrow
136 .getattr("Array")?
137 .call_method1("_import_from_c", (array_ptr, schema_ptr))?;
138
139 let repr: String = pa_array.call_method0("__repr__")?.extract()?;
140 println!(" PyArrow received: {}", repr.lines().next().unwrap_or(""));
141 println!(" Done.\n");
142 Ok(())
143}
144
145fn example_2_export_table_stream(py: Python<'_>) -> PyResult<()> {
150 println!("Example 2: Export MinArrow table -> PyArrow via __arrow_c_stream__");
151 println!("------------------------------------------------------------------");
152
153 let mut ids = IntegerArray::<i32>::default();
154 ids.push(1);
155 ids.push(2);
156 ids.push(3);
157
158 let mut scores = FloatArray::<f64>::default();
159 scores.push(9.5);
160 scores.push(8.3);
161 scores.push(7.1);
162
163 let table = Table::new(
164 "results".to_string(),
165 Some(vec![
166 FieldArray::new(
167 Field::new("id", ArrowType::Int32, false, None),
168 Array::from_int32(ids),
169 ),
170 FieldArray::new(
171 Field::new("score", ArrowType::Float64, false, None),
172 Array::from_float64(scores),
173 ),
174 ]),
175 );
176 println!(" Created MinArrow table: 3 rows x 2 columns (id, score)");
177
178 let stream_capsule = to_py::table_to_stream_capsule(&table, py)?;
180 let stream_ptr = unsafe {
181 pyo3::ffi::PyCapsule_GetPointer(
182 stream_capsule.as_ptr(),
183 c"arrow_array_stream".as_ptr(),
184 )
185 } as usize;
186
187 let pyarrow = py.import("pyarrow")?;
188 let reader = pyarrow
189 .getattr("RecordBatchReader")?
190 .call_method1("_import_from_c", (stream_ptr,))?;
191 let pa_table = reader.call_method0("read_all")?;
192
193 let num_rows: usize = pa_table.getattr("num_rows")?.extract()?;
194 let schema_repr: String = pa_table.getattr("schema")?.call_method0("__repr__")?.extract()?;
195 println!(" PyArrow received: {} rows", num_rows);
196 println!(" Schema: {}", schema_repr.lines().next().unwrap_or(""));
197 println!(" Done.\n");
198 Ok(())
199}
200
201fn example_3_import_from_pyarrow_array(py: Python<'_>) -> PyResult<()> {
207 println!("Example 3: Import PyArrow array -> MinArrow via __arrow_c_array__");
208 println!("-----------------------------------------------------------------");
209
210 let pyarrow = py.import("pyarrow")?;
211 let py_array = pyarrow.call_method1("array", (vec![100i64, 200, 300, 400, 500],))?;
212 println!(" Created PyArrow array: [100, 200, 300, 400, 500]");
213
214 let result = to_rust::try_capsule_array(&py_array);
215
216 match result {
217 Some(Ok(field_array)) => {
218 println!(" Imported into MinArrow: {} elements", field_array.array.len());
219
220 match &field_array.array {
221 Array::NumericArray(NumericArray::Int64(a)) => {
222 let values: Vec<i64> = (0..a.len())
223 .map(|i| a.get(i).unwrap_or(0))
224 .collect();
225 println!(" Values: {:?}", values);
226 }
227 other => println!(" Got type: {:?}", std::mem::discriminant(other)),
228 }
229 }
230 Some(Err(e)) => println!(" Import failed: {}", e),
231 None => println!(" __arrow_c_array__ not available on this object"),
232 }
233
234 println!(" Done.\n");
235 Ok(())
236}
237
238fn example_4_import_from_pyarrow_table(py: Python<'_>) -> PyResult<()> {
243 println!("Example 4: Import PyArrow table -> MinArrow via __arrow_c_stream__");
244 println!("------------------------------------------------------------------");
245
246 let pyarrow = py.import("pyarrow")?;
247 let dict = vec![
248 (
249 "name",
250 pyarrow.call_method1("array", (vec!["Alice", "Bob", "Charlie"],))?,
251 ),
252 (
253 "age",
254 pyarrow.call_method1("array", (vec![30i64, 25, 35],))?,
255 ),
256 ]
257 .into_py_dict(py)?;
258
259 let py_table = pyarrow.call_method1("table", (dict,))?;
260 println!(" Created PyArrow table: name=['Alice','Bob','Charlie'], age=[30,25,35]");
261
262 let result = to_rust::try_capsule_record_batch_stream(&py_table);
263
264 match result {
265 Some(Ok((batches, _metadata))) => {
266 println!(" Imported {} batch(es) into MinArrow", batches.len());
267 for (batch_idx, batch) in batches.iter().enumerate() {
268 println!(" Batch {}: {} columns", batch_idx, batch.len());
269 for (col_idx, (array, field)) in batch.iter().enumerate() {
270 println!(
271 " Column {} '{}': {} rows, type={:?}",
272 col_idx,
273 field.name,
274 array.len(),
275 field.dtype
276 );
277 }
278 }
279 }
280 Some(Err(e)) => println!(" Import failed: {}", e),
281 None => println!(" __arrow_c_stream__ not available on this object"),
282 }
283
284 println!(" Done.\n");
285 Ok(())
286}