use std::slice;
use pyo3::{ffi, pyobject_native_type_named, Bound, PyAny, PyTypeInfo, Python};
use crate::array::{PyArray, PyArrayMethods};
use crate::cold;
use crate::dtype::PyArrayDescr;
use crate::npyffi;
#[repr(transparent)]
pub struct PyUntypedArray(PyAny);
unsafe impl PyTypeInfo for PyUntypedArray {
const NAME: &'static str = "PyUntypedArray";
const MODULE: Option<&'static str> = Some("numpy");
fn type_object_raw<'py>(py: Python<'py>) -> *mut ffi::PyTypeObject {
unsafe { npyffi::PY_ARRAY_API.get_type_object(py, npyffi::NpyTypes::PyArray_Type) }
}
fn is_type_of(ob: &Bound<'_, PyAny>) -> bool {
unsafe { npyffi::PyArray_Check(ob.py(), ob.as_ptr()) != 0 }
}
}
pyobject_native_type_named!(PyUntypedArray);
#[doc(alias = "PyUntypedArray")]
pub trait PyUntypedArrayMethods<'py>: Sealed {
fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject;
fn dtype(&self) -> Bound<'py, PyArrayDescr>;
fn is_contiguous(&self) -> bool {
unsafe {
check_flags(
&*self.as_array_ptr(),
npyffi::NPY_ARRAY_C_CONTIGUOUS | npyffi::NPY_ARRAY_F_CONTIGUOUS,
)
}
}
fn is_fortran_contiguous(&self) -> bool {
unsafe { check_flags(&*self.as_array_ptr(), npyffi::NPY_ARRAY_F_CONTIGUOUS) }
}
fn is_c_contiguous(&self) -> bool {
unsafe { check_flags(&*self.as_array_ptr(), npyffi::NPY_ARRAY_C_CONTIGUOUS) }
}
#[inline]
fn ndim(&self) -> usize {
unsafe { (*self.as_array_ptr()).nd as usize }
}
#[inline]
fn strides(&self) -> &[isize] {
let n = self.ndim();
if n == 0 {
cold();
return &[];
}
let ptr = self.as_array_ptr();
unsafe {
let p = (*ptr).strides;
slice::from_raw_parts(p, n)
}
}
#[inline]
fn shape(&self) -> &[usize] {
let n = self.ndim();
if n == 0 {
cold();
return &[];
}
let ptr = self.as_array_ptr();
unsafe {
let p = (*ptr).dimensions as *mut usize;
slice::from_raw_parts(p, n)
}
}
fn len(&self) -> usize {
self.shape().iter().product()
}
fn is_empty(&self) -> bool {
self.shape().contains(&0)
}
}
mod sealed {
pub trait Sealed {}
}
use sealed::Sealed;
fn check_flags(obj: &npyffi::PyArrayObject, flags: i32) -> bool {
obj.flags & flags != 0
}
impl<'py> PyUntypedArrayMethods<'py> for Bound<'py, PyUntypedArray> {
#[inline]
fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject {
self.as_ptr().cast()
}
fn dtype(&self) -> Bound<'py, PyArrayDescr> {
unsafe {
let descr_ptr = (*self.as_array_ptr()).descr;
Bound::from_borrowed_ptr(self.py(), descr_ptr.cast()).cast_into_unchecked()
}
}
}
impl Sealed for Bound<'_, PyUntypedArray> {}
impl<'py, T, D> PyUntypedArrayMethods<'py> for Bound<'py, PyArray<T, D>> {
#[inline]
fn as_array_ptr(&self) -> *mut npyffi::PyArrayObject {
self.as_untyped().as_array_ptr()
}
#[inline]
fn dtype(&self) -> Bound<'py, PyArrayDescr> {
self.as_untyped().dtype()
}
}
impl<T, D> Sealed for Bound<'_, PyArray<T, D>> {}