use std::sync::Arc;
use arrow_array::{ArrayRef, RecordBatch, RecordBatchReader};
use arrow_schema::{DataType, Field, FieldRef, Schema, SchemaRef};
use pyo3::intern;
use pyo3::prelude::*;
use pyo3::types::PyTuple;
use crate::ffi::{to_array_pycapsules, to_schema_pycapsule, to_stream_pycapsule, ArrayReader};
use crate::{
PyArray, PyArrayReader, PyChunkedArray, PyDataType, PyField, PyRecordBatch,
PyRecordBatchReader, PyScalar, PySchema, PyTable,
};
#[derive(Debug)]
pub struct Arro3Array(PyArray);
impl From<PyArray> for Arro3Array {
fn from(value: PyArray) -> Self {
Self(value)
}
}
impl From<ArrayRef> for Arro3Array {
fn from(value: ArrayRef) -> Self {
Self(value.into())
}
}
impl<'py> IntoPyObject<'py> for Arro3Array {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod.getattr(intern!(py, "Array"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
to_array_pycapsules(py, self.0.field().clone(), &self.0.array(), None)?,
)
}
}
pub struct Arro3ArrayReader(PyArrayReader);
impl From<PyArrayReader> for Arro3ArrayReader {
fn from(value: PyArrayReader) -> Self {
Self(value)
}
}
impl From<Box<dyn ArrayReader + Send>> for Arro3ArrayReader {
fn from(value: Box<dyn ArrayReader + Send>) -> Self {
Self(value.into())
}
}
impl<'py> IntoPyObject<'py> for Arro3ArrayReader {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
let capsule = to_stream_pycapsule(py, self.0.into_reader()?, None)?;
arro3_mod.getattr(intern!(py, "ArrayReader"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, [capsule])?,
)
}
}
#[derive(Debug)]
pub struct Arro3ChunkedArray(PyChunkedArray);
impl From<PyChunkedArray> for Arro3ChunkedArray {
fn from(value: PyChunkedArray) -> Self {
Self(value)
}
}
impl<'py> IntoPyObject<'py> for Arro3ChunkedArray {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let capsule = PyChunkedArray::to_stream_pycapsule(
py,
self.0.chunks().to_vec(),
self.0.field().clone(),
None,
)?;
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod
.getattr(intern!(py, "ChunkedArray"))?
.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![capsule])?,
)
}
}
#[derive(Debug)]
pub struct Arro3Field(PyField);
impl From<PyField> for Arro3Field {
fn from(value: PyField) -> Self {
Self(value)
}
}
impl From<FieldRef> for Arro3Field {
fn from(value: FieldRef) -> Self {
Self(value.into())
}
}
impl From<&Field> for Arro3Field {
fn from(value: &Field) -> Self {
Self(Arc::new(value.clone()).into())
}
}
impl<'py> IntoPyObject<'py> for Arro3Field {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod.getattr(intern!(py, "Field"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![to_schema_pycapsule(py, self.0.as_ref())?])?,
)
}
}
#[derive(Debug)]
pub struct Arro3DataType(PyDataType);
impl From<PyDataType> for Arro3DataType {
fn from(value: PyDataType) -> Self {
Self(value)
}
}
impl From<DataType> for Arro3DataType {
fn from(value: DataType) -> Self {
Self(PyDataType::new(value))
}
}
impl<'py> IntoPyObject<'py> for Arro3DataType {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod.getattr(intern!(py, "DataType"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![to_schema_pycapsule(py, self.0.as_ref())?])?,
)
}
}
#[derive(Debug)]
pub struct Arro3RecordBatch(PyRecordBatch);
impl From<PyRecordBatch> for Arro3RecordBatch {
fn from(value: PyRecordBatch) -> Self {
Self(value)
}
}
impl From<RecordBatch> for Arro3RecordBatch {
fn from(value: RecordBatch) -> Self {
Self(value.into())
}
}
impl<'py> IntoPyObject<'py> for Arro3RecordBatch {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
let capsules = PyRecordBatch::to_array_pycapsules(py, self.0.into_inner(), None)?;
arro3_mod
.getattr(intern!(py, "RecordBatch"))?
.call_method1(intern!(py, "from_arrow_pycapsule"), capsules)
}
}
pub struct Arro3RecordBatchReader(PyRecordBatchReader);
impl From<PyRecordBatchReader> for Arro3RecordBatchReader {
fn from(value: PyRecordBatchReader) -> Self {
Self(value)
}
}
impl From<Box<dyn RecordBatchReader + Send>> for Arro3RecordBatchReader {
fn from(value: Box<dyn RecordBatchReader + Send>) -> Self {
Self(PyRecordBatchReader::new(value))
}
}
impl<'py> IntoPyObject<'py> for Arro3RecordBatchReader {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
let capsule = PyRecordBatchReader::to_stream_pycapsule(py, self.0.into_reader()?, None)?;
arro3_mod
.getattr(intern!(py, "RecordBatchReader"))?
.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![capsule])?,
)
}
}
#[derive(Debug)]
pub struct Arro3Scalar(PyScalar);
impl From<PyScalar> for Arro3Scalar {
fn from(value: PyScalar) -> Self {
Self(value)
}
}
impl<'py> IntoPyObject<'py> for Arro3Scalar {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let capsules = to_array_pycapsules(py, self.0.field().clone(), &self.0.array(), None)?;
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod
.getattr(intern!(py, "Scalar"))?
.call_method1(intern!(py, "from_arrow_pycapsule"), capsules)
}
}
#[derive(Debug)]
pub struct Arro3Schema(PySchema);
impl From<PySchema> for Arro3Schema {
fn from(value: PySchema) -> Self {
Self(value)
}
}
impl From<SchemaRef> for Arro3Schema {
fn from(value: SchemaRef) -> Self {
Self(PySchema::new(value))
}
}
impl From<Schema> for Arro3Schema {
fn from(value: Schema) -> Self {
Self(PySchema::new(Arc::new(value)))
}
}
impl<'py> IntoPyObject<'py> for Arro3Schema {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
arro3_mod.getattr(intern!(py, "Schema"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![to_schema_pycapsule(py, self.0.as_ref())?])?,
)
}
}
#[derive(Debug)]
pub struct Arro3Table(PyTable);
impl Arro3Table {
pub(crate) fn into_inner(self) -> PyTable {
self.0
}
}
impl From<PyTable> for Arro3Table {
fn from(value: PyTable) -> Self {
Self(value)
}
}
impl<'py> IntoPyObject<'py> for Arro3Table {
type Target = PyAny;
type Output = Bound<'py, PyAny>;
type Error = PyErr;
fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
let arro3_mod = py.import(intern!(py, "arro3.core"))?;
let (batches, schema) = self.0.into_inner();
let capsule = PyTable::to_stream_pycapsule(py, batches, schema, None)?;
arro3_mod.getattr(intern!(py, "Table"))?.call_method1(
intern!(py, "from_arrow_pycapsule"),
PyTuple::new(py, vec![capsule])?,
)
}
}