Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use crate::error::{
AsSliceError, BorrowError, DimensionalityError, FromVecError, IgnoreError, TypeError,
DIMENSIONALITY_MISMATCH_ERR, MAX_DIMENSIONALITY_ERR,
};
use crate::npyffi::{self, npy_intp, NPY_ORDER, PY_ARRAY_API};
use crate::npyffi::{self, _PyArray_GET_ITEM_DATA, npy_intp, NPY_ORDER, PY_ARRAY_API};
use crate::slice_container::PySliceContainer;
use crate::untyped_array::{PyUntypedArray, PyUntypedArrayMethods};

Expand Down Expand Up @@ -1483,7 +1483,7 @@ impl<'py, T, D> PyArrayMethods<'py, T, D> for Bound<'py, PyArray<T, D>> {

#[inline(always)]
fn data(&self) -> *mut T {
unsafe { (*self.as_array_ptr()).data.cast() }
unsafe { (*_PyArray_GET_ITEM_DATA(self.as_array_ptr())).data.cast() }
}

#[inline(always)]
Expand Down
4 changes: 2 additions & 2 deletions src/borrow/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ use crate::array::{PyArray, PyArrayMethods};
use crate::convert::NpyIndex;
use crate::dtype::Element;
use crate::error::{AsSliceError, BorrowError};
use crate::npyffi::flags;
use crate::npyffi::{_PyArray_GET_ITEM_DATA, flags};
use crate::untyped_array::PyUntypedArrayMethods;

use shared::{acquire, acquire_mut, release, release_mut};
Expand Down Expand Up @@ -537,7 +537,7 @@ where
// SAFETY: consuming the only extant mutable reference guarantees we cannot invalidate an
// existing reference, nor allow the caller to keep hold of one.
unsafe {
(*self.as_array_ptr()).flags &= !flags::NPY_ARRAY_WRITEABLE;
(*_PyArray_GET_ITEM_DATA(self.as_array_ptr())).flags &= !flags::NPY_ARRAY_WRITEABLE;
}
self.into()
}
Expand Down
12 changes: 8 additions & 4 deletions src/borrow/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ use rustc_hash::FxHashMap;
use crate::array::get_array_module;
use crate::cold;
use crate::error::BorrowError;
use crate::npyffi::{PyArrayObject, PyArray_Check, PyDataType_ELSIZE, NPY_ARRAY_WRITEABLE};
use crate::npyffi::{
_PyArray_GET_ITEM_DATA, PyArrayObject, PyArray_Check, PyDataType_ELSIZE, NPY_ARRAY_WRITEABLE,
};

/// Defines the shared C API used for borrow checking
///
Expand Down Expand Up @@ -57,7 +59,7 @@ unsafe extern "C" fn acquire_shared(flags: *mut c_void, array: *mut PyArrayObjec
}

unsafe extern "C" fn acquire_mut_shared(flags: *mut c_void, array: *mut PyArrayObject) -> c_int {
if (*array).flags & NPY_ARRAY_WRITEABLE == 0 {
if (*_PyArray_GET_ITEM_DATA(array)).flags & NPY_ARRAY_WRITEABLE == 0 {
return -2;
}

Expand Down Expand Up @@ -368,7 +370,7 @@ impl BorrowFlags {

fn base_address<'py>(py: Python<'py>, mut array: *mut PyArrayObject) -> *mut c_void {
loop {
let base = unsafe { (*array).base };
let base = unsafe { (*_PyArray_GET_ITEM_DATA(array)).base };

if base.is_null() {
return array as *mut c_void;
Expand All @@ -383,7 +385,7 @@ fn base_address<'py>(py: Python<'py>, mut array: *mut PyArrayObject) -> *mut c_v
fn borrow_key<'py>(py: Python<'py>, array: *mut PyArrayObject) -> BorrowKey {
let range = data_range(py, array);

let data_ptr = unsafe { (*array).data };
let data_ptr = unsafe { (*_PyArray_GET_ITEM_DATA(array)).data };
let gcd_strides = gcd_strides(array);

BorrowKey {
Expand All @@ -394,6 +396,7 @@ fn borrow_key<'py>(py: Python<'py>, array: *mut PyArrayObject) -> BorrowKey {
}

fn data_range<'py>(py: Python<'py>, array: *mut PyArrayObject) -> (*mut c_char, *mut c_char) {
let array = unsafe { _PyArray_GET_ITEM_DATA(array) };
let nd = unsafe { (*array).nd } as usize;
let data = unsafe { (*array).data };

Expand Down Expand Up @@ -430,6 +433,7 @@ fn data_range<'py>(py: Python<'py>, array: *mut PyArrayObject) -> (*mut c_char,
}

fn gcd_strides(array: *mut PyArrayObject) -> isize {
let array = unsafe { _PyArray_GET_ITEM_DATA(array) };
let nd = unsafe { (*array).nd } as usize;

if nd == 0 {
Expand Down
22 changes: 14 additions & 8 deletions src/dtype.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ use pyo3::{
};

use crate::npyffi::{
self, NpyTypes, PyArray_Descr, PyDataType_ALIGNMENT, PyDataType_ELSIZE, PyDataType_FIELDS,
PyDataType_FLAGS, PyDataType_NAMES, PyDataType_SUBARRAY, NPY_ALIGNED_STRUCT,
NPY_BYTEORDER_CHAR, NPY_ITEM_HASOBJECT, NPY_TYPES, PY_ARRAY_API,
self, _PyDataType_GET_ITEM_DATA, NpyTypes, PyArray_Descr, PyDataType_ALIGNMENT,
PyDataType_ELSIZE, PyDataType_FIELDS, PyDataType_FLAGS, PyDataType_NAMES, PyDataType_SUBARRAY,
NPY_ALIGNED_STRUCT, NPY_BYTEORDER_CHAR, NPY_ITEM_HASOBJECT, NPY_TYPES, PY_ARRAY_API,
};

pub use num_complex::{Complex32, Complex64};
Expand Down Expand Up @@ -159,7 +159,7 @@ pub trait PyArrayDescrMethods<'py>: Sealed {
/// [enumerated-types]: https://numpy.org/doc/stable/reference/c-api/dtype.html#enumerated-types
/// [dtype-num]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.num.html
fn num(&self) -> c_int {
unsafe { &*self.as_dtype_ptr() }.type_num
unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }.type_num
}

/// Returns the element size of this type descriptor.
Expand All @@ -184,7 +184,9 @@ pub trait PyArrayDescrMethods<'py>: Sealed {
///
/// [dtype-byteorder]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.byteorder.html
fn byteorder(&self) -> u8 {
unsafe { &*self.as_dtype_ptr() }.byteorder.max(0) as _
unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }
.byteorder
.max(0) as _
}

/// Returns a unique ASCII character for each of the 21 different built-in types.
Expand All @@ -195,7 +197,9 @@ pub trait PyArrayDescrMethods<'py>: Sealed {
///
/// [dtype-char]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.char.html
fn char(&self) -> u8 {
unsafe { &*self.as_dtype_ptr() }.type_.max(0) as _
unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }
.type_
.max(0) as _
}

/// Returns an ASCII character (one of `biufcmMOSUV`) identifying the general kind of data.
Expand All @@ -206,7 +210,9 @@ pub trait PyArrayDescrMethods<'py>: Sealed {
///
/// [dtype-kind]: https://numpy.org/doc/stable/reference/generated/numpy.dtype.kind.html
fn kind(&self) -> u8 {
unsafe { &*self.as_dtype_ptr() }.kind.max(0) as _
unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }
.kind
.max(0) as _
}

/// Returns bit-flags describing how this type descriptor is to be interpreted.
Expand Down Expand Up @@ -330,7 +336,7 @@ impl<'py> PyArrayDescrMethods<'py> for Bound<'py, PyArrayDescr> {
}

fn typeobj(&self) -> Bound<'py, PyType> {
let dtype_type_ptr = unsafe { &*self.as_dtype_ptr() }.typeobj;
let dtype_type_ptr = unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }.typeobj;
unsafe { PyType::from_borrowed_type_ptr(self.py(), dtype_type_ptr) }
}

Expand Down
16 changes: 16 additions & 0 deletions src/npyffi/array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,22 @@ impl PyArrayAPI {
// Min v2.0 impl_api![363; PyArray_CommonDType(dtype1: *mut PyArray_DTypeMeta, dtype2: *mut PyArray_DTypeMeta) -> PyArray_DTypeMeta];
// Min v2.0 impl_api![364; PyArray_PromoteDTypeSequence(length: npy_intp, dtypes_in: *mut *mut PyArray_DTypeMeta) -> *mut PyArray_DTypeMeta];
// Min v2.0 impl_api![365; _PyDataType_GetArrFuncs(descr: *const PyArray_Descr) -> *mut PyArray_ArrFuncs];
// Slot 366, 367, 368 are the abstract DTypes
}

// Min v2.5
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
impl PyArrayAPI {
impl_api![369; _PyArray_GET_ITEM_DATA(arr: *const PyArrayObject) -> *mut PyArrayObject_fields];
// impl_api![370; _PyArrayIter_GET_ITEM_DATA(iter: *const PyArrayIterObject) -> *mut PyArrayIterObject_fields];
// impl_api![371; _PyArray_LegacyDescr_GET_ITEM_DATA(dtype: *const _PyArray_LegacyDescr) -> *mut _PyArray_LegacyDescr_fields];
impl_api![372; _PyDataType_GET_ITEM_DATA(dtype: *const PyArray_Descr) -> *mut PyArray_Descr_fields];
// impl_api![373; _PyArrayMultiIter_GET_ITEM_DATA(multi: *const PyArrayMultiIterObject) -> *mut PyArrayMultiIterObject_fields];
// impl_api![374; _PyArrayNeighborhoodIter_GET_ITEM_DATA(iter: *const PyArrayNeighborhoodIterObject) -> *mut PyArrayNeighborhoodIterObject_fields];
// impl_api![375; _PyDatetimeScalarObject_GetMetadata(obj: *mut PyObject) -> *mut PyArray_DatetimeMetaData];
// impl_api![376; _PyTimedeltaScalarObject_GetMetadata(obj: *mut PyObject) -> *mut PyArray_DatetimeMetaData];
// impl_api![377; _PyDatetimeScalarObject_GetValue(obj: *mut PyObject) -> npy_datetime];
// impl_api![378; _PyTimedeltaScalarObject_GetValue(obj: *mut PyObject) -> npy_datetime];
}

/// Checks that `op` is an instance of `PyArray` or not.
Expand Down
54 changes: 52 additions & 2 deletions src/npyffi/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ pub const NPY_NTYPES_ABI_COMPATIBLE: usize = 21;
pub const NPY_MAXDIMS_LEGACY_ITERS: usize = 32;

#[repr(C)]
pub struct PyArrayObject {
pub struct PyArrayObject_fields {
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
pub ob_base: PyObject,
pub data: *mut c_char,
pub nd: c_int,
Expand All @@ -26,8 +27,19 @@ pub struct PyArrayObject {
pub weakreflist: *mut PyObject,
}

#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
pub type PyArrayObject = PyArrayObject_fields;

#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
#[repr(C)]
pub struct PyArray_Descr {
pub struct PyArrayObject {
_data: (),
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[repr(C)]
pub struct PyArray_Descr_fields {
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
pub ob_base: PyObject,
pub typeobj: *mut PyTypeObject,
pub kind: c_char,
Expand All @@ -37,6 +49,16 @@ pub struct PyArray_Descr {
pub type_num: c_int,
}

#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
pub type PyArray_Descr = PyArray_Descr_fields;

#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
#[repr(C)]
pub struct PyArray_Descr {
_data: (),
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}

#[repr(C)]
pub struct PyArray_DescrProto {
pub ob_base: PyObject,
Expand Down Expand Up @@ -76,6 +98,7 @@ pub struct _PyArray_DescrNumPy2 {

#[repr(C)]
struct _PyArray_LegacyDescr {
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
pub ob_base: PyObject,
pub typeobj: *mut PyTypeObject,
pub kind: c_char,
Expand All @@ -95,9 +118,36 @@ struct _PyArray_LegacyDescr {
pub c_metadata: *mut NpyAuxData,
}

#[allow(non_snake_case)]
#[inline(always)]
pub unsafe fn _PyArray_GET_ITEM_DATA(arr: *const PyArrayObject) -> *mut PyArrayObject_fields {
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
{
PY_ARRAY_API._PyArray_GET_ITEM_DATA(Python::assume_attached(), arr)
}
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
{
arr.cast_mut().cast()
}
}

#[allow(non_snake_case)]
#[inline(always)]
pub unsafe fn _PyDataType_GET_ITEM_DATA(dtype: *const PyArray_Descr) -> *mut PyArray_Descr_fields {
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
{
PY_ARRAY_API._PyDataType_GET_ITEM_DATA(Python::assume_attached(), dtype)
}
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
{
dtype.cast_mut().cast()
}
}

#[allow(non_snake_case)]
#[inline(always)]
pub unsafe fn PyDataType_ISLEGACY(dtype: *const PyArray_Descr) -> bool {
let dtype = _PyDataType_GET_ITEM_DATA(dtype);
(*dtype).type_num < NPY_TYPES::NPY_VSTRING as _ && (*dtype).type_num >= 0
}

Expand Down
5 changes: 2 additions & 3 deletions src/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ use pyo3::{
use rustc_hash::FxHashMap;

use crate::dtype::{clone_methods_impl, Element, PyArrayDescr, PyArrayDescrMethods};
use crate::npyffi::PyDataType_SET_ELSIZE;
use crate::npyffi::NPY_TYPES;
use crate::npyffi::{_PyDataType_GET_ITEM_DATA, PyDataType_SET_ELSIZE, NPY_TYPES};

/// A newtype wrapper around [`[u8; N]`][Py_UCS1] to handle [`byte` scalars][numpy-bytes] while satisfying coherence.
///
Expand Down Expand Up @@ -191,7 +190,7 @@ impl TypeDescriptors {

let descr = &mut *dtype.as_dtype_ptr();
PyDataType_SET_ELSIZE(py, descr, size.try_into().unwrap());
descr.byteorder = byteorder;
(*_PyDataType_GET_ITEM_DATA(descr)).byteorder = byteorder;

entry.insert(dtype.into())
}
Expand Down
13 changes: 7 additions & 6 deletions src/untyped_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ 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;
use crate::npyffi::{self, _PyArray_GET_ITEM_DATA};

/// A safe, untyped wrapper for NumPy's [`ndarray`] class.
///
Expand Down Expand Up @@ -197,7 +197,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed {
/// [PyArray_NDIM]: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_NDIM
#[inline]
fn ndim(&self) -> usize {
unsafe { (*self.as_array_ptr()).nd as usize }
unsafe { (*_PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const())).nd as usize }
}

/// Returns a slice indicating how many bytes to advance when iterating along each axis.
Expand Down Expand Up @@ -225,7 +225,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed {
cold();
return &[];
}
let ptr = self.as_array_ptr();
let ptr = unsafe { _PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const()) };
unsafe {
let p = (*ptr).strides;
slice::from_raw_parts(p, n)
Expand Down Expand Up @@ -258,7 +258,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed {
cold();
return &[];
}
let ptr = self.as_array_ptr();
let ptr = unsafe { _PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const()) };
unsafe {
let p = (*ptr).dimensions as *mut usize;
slice::from_raw_parts(p, n)
Expand All @@ -283,7 +283,7 @@ mod sealed {
use sealed::Sealed;

fn check_flags(obj: &npyffi::PyArrayObject, flags: i32) -> bool {
obj.flags & flags != 0
unsafe { (*_PyArray_GET_ITEM_DATA(obj)).flags & flags != 0 }
}

impl<'py> PyUntypedArrayMethods<'py> for Bound<'py, PyUntypedArray> {
Expand All @@ -294,7 +294,8 @@ impl<'py> PyUntypedArrayMethods<'py> for Bound<'py, PyUntypedArray> {

fn dtype(&self) -> Bound<'py, PyArrayDescr> {
unsafe {
let descr_ptr = (*self.as_array_ptr()).descr;
let descr_ptr =
(*npyffi::_PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const())).descr;
Bound::from_borrowed_ptr(self.py(), descr_ptr.cast()).cast_into_unchecked()
}
}
Expand Down
Loading