Skip to content

Commit e086d8e

Browse files
committed
WIP: add support for abi3t
1 parent 4ef0102 commit e086d8e

8 files changed

Lines changed: 103 additions & 27 deletions

File tree

src/array.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ use crate::error::{
2828
AsSliceError, BorrowError, DimensionalityError, FromVecError, IgnoreError, TypeError,
2929
DIMENSIONALITY_MISMATCH_ERR, MAX_DIMENSIONALITY_ERR,
3030
};
31-
use crate::npyffi::{self, npy_intp, NPY_ORDER, PY_ARRAY_API};
31+
use crate::npyffi::{self, _PyArray_GET_ITEM_DATA, npy_intp, NPY_ORDER, PY_ARRAY_API};
3232
use crate::slice_container::PySliceContainer;
3333
use crate::untyped_array::{PyUntypedArray, PyUntypedArrayMethods};
3434

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

14841484
#[inline(always)]
14851485
fn data(&self) -> *mut T {
1486-
unsafe { (*self.as_array_ptr()).data.cast() }
1486+
unsafe { (*_PyArray_GET_ITEM_DATA(self.as_array_ptr())).data.cast() }
14871487
}
14881488

14891489
#[inline(always)]

src/borrow/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ use crate::array::{PyArray, PyArrayMethods};
181181
use crate::convert::NpyIndex;
182182
use crate::dtype::Element;
183183
use crate::error::{AsSliceError, BorrowError};
184-
use crate::npyffi::flags;
184+
use crate::npyffi::{_PyArray_GET_ITEM_DATA, flags};
185185
use crate::untyped_array::PyUntypedArrayMethods;
186186

187187
use shared::{acquire, acquire_mut, release, release_mut};
@@ -537,7 +537,7 @@ where
537537
// SAFETY: consuming the only extant mutable reference guarantees we cannot invalidate an
538538
// existing reference, nor allow the caller to keep hold of one.
539539
unsafe {
540-
(*self.as_array_ptr()).flags &= !flags::NPY_ARRAY_WRITEABLE;
540+
(*_PyArray_GET_ITEM_DATA(self.as_array_ptr())).flags &= !flags::NPY_ARRAY_WRITEABLE;
541541
}
542542
self.into()
543543
}

src/borrow/shared.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ use rustc_hash::FxHashMap;
1515
use crate::array::get_array_module;
1616
use crate::cold;
1717
use crate::error::BorrowError;
18-
use crate::npyffi::{PyArrayObject, PyArray_Check, PyDataType_ELSIZE, NPY_ARRAY_WRITEABLE};
18+
use crate::npyffi::{
19+
_PyArray_GET_ITEM_DATA, PyArrayObject, PyArray_Check, PyDataType_ELSIZE, NPY_ARRAY_WRITEABLE,
20+
};
1921

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

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

@@ -368,7 +370,7 @@ impl BorrowFlags {
368370

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

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

386-
let data_ptr = unsafe { (*array).data };
388+
let data_ptr = unsafe { (*_PyArray_GET_ITEM_DATA(array)).data };
387389
let gcd_strides = gcd_strides(array);
388390

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

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

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

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

435439
if nd == 0 {

src/dtype.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ use pyo3::{
1717
};
1818

1919
use crate::npyffi::{
20-
self, NpyTypes, PyArray_Descr, PyDataType_ALIGNMENT, PyDataType_ELSIZE, PyDataType_FIELDS,
21-
PyDataType_FLAGS, PyDataType_NAMES, PyDataType_SUBARRAY, NPY_ALIGNED_STRUCT,
22-
NPY_BYTEORDER_CHAR, NPY_ITEM_HASOBJECT, NPY_TYPES, PY_ARRAY_API,
20+
self, _PyDataType_GET_ITEM_DATA, NpyTypes, PyArray_Descr, PyDataType_ALIGNMENT,
21+
PyDataType_ELSIZE, PyDataType_FIELDS, PyDataType_FLAGS, PyDataType_NAMES, PyDataType_SUBARRAY,
22+
NPY_ALIGNED_STRUCT, NPY_BYTEORDER_CHAR, NPY_ITEM_HASOBJECT, NPY_TYPES, PY_ARRAY_API,
2323
};
2424

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

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

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

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

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

332338
fn typeobj(&self) -> Bound<'py, PyType> {
333-
let dtype_type_ptr = unsafe { &*self.as_dtype_ptr() }.typeobj;
339+
let dtype_type_ptr = unsafe { &*_PyDataType_GET_ITEM_DATA(self.as_dtype_ptr()) }.typeobj;
334340
unsafe { PyType::from_borrowed_type_ptr(self.py(), dtype_type_ptr) }
335341
}
336342

src/npyffi/array.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,22 @@ impl PyArrayAPI {
428428
// Min v2.0 impl_api![363; PyArray_CommonDType(dtype1: *mut PyArray_DTypeMeta, dtype2: *mut PyArray_DTypeMeta) -> PyArray_DTypeMeta];
429429
// Min v2.0 impl_api![364; PyArray_PromoteDTypeSequence(length: npy_intp, dtypes_in: *mut *mut PyArray_DTypeMeta) -> *mut PyArray_DTypeMeta];
430430
// Min v2.0 impl_api![365; _PyDataType_GetArrFuncs(descr: *const PyArray_Descr) -> *mut PyArray_ArrFuncs];
431+
// Slot 366, 367, 368 are the abstract DTypes
432+
}
433+
434+
// Min v2.5
435+
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
436+
impl PyArrayAPI {
437+
impl_api![369; _PyArray_GET_ITEM_DATA(arr: *const PyArrayObject) -> *mut PyArrayObject_fields];
438+
// impl_api![370; _PyArrayIter_GET_ITEM_DATA(iter: *const PyArrayIterObject) -> *mut PyArrayIterObject_fields];
439+
// impl_api![371; _PyArray_LegacyDescr_GET_ITEM_DATA(dtype: *const _PyArray_LegacyDescr) -> *mut _PyArray_LegacyDescr_fields];
440+
impl_api![372; _PyDataType_GET_ITEM_DATA(dtype: *const PyArray_Descr) -> *mut PyArray_Descr_fields];
441+
// impl_api![373; _PyArrayMultiIter_GET_ITEM_DATA(multi: *const PyArrayMultiIterObject) -> *mut PyArrayMultiIterObject_fields];
442+
// impl_api![374; _PyArrayNeighborhoodIter_GET_ITEM_DATA(iter: *const PyArrayNeighborhoodIterObject) -> *mut PyArrayNeighborhoodIterObject_fields];
443+
// impl_api![375; _PyDatetimeScalarObject_GetMetadata(obj: *mut PyObject) -> *mut PyArray_DatetimeMetaData];
444+
// impl_api![376; _PyTimedeltaScalarObject_GetMetadata(obj: *mut PyObject) -> *mut PyArray_DatetimeMetaData];
445+
// impl_api![377; _PyDatetimeScalarObject_GetValue(obj: *mut PyObject) -> npy_datetime];
446+
// impl_api![378; _PyTimedeltaScalarObject_GetValue(obj: *mut PyObject) -> npy_datetime];
431447
}
432448

433449
/// Checks that `op` is an instance of `PyArray` or not.

src/npyffi/objects.rs

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ pub const NPY_NTYPES_ABI_COMPATIBLE: usize = 21;
1414
pub const NPY_MAXDIMS_LEGACY_ITERS: usize = 32;
1515

1616
#[repr(C)]
17-
pub struct PyArrayObject {
17+
pub struct PyArrayObject_fields {
18+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
1819
pub ob_base: PyObject,
1920
pub data: *mut c_char,
2021
pub nd: c_int,
@@ -26,8 +27,19 @@ pub struct PyArrayObject {
2627
pub weakreflist: *mut PyObject,
2728
}
2829

30+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
31+
pub type PyArrayObject = PyArrayObject_fields;
32+
33+
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
2934
#[repr(C)]
30-
pub struct PyArray_Descr {
35+
pub struct PyArrayObject {
36+
_data: (),
37+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
38+
}
39+
40+
#[repr(C)]
41+
pub struct PyArray_Descr_fields {
42+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
3143
pub ob_base: PyObject,
3244
pub typeobj: *mut PyTypeObject,
3345
pub kind: c_char,
@@ -37,6 +49,16 @@ pub struct PyArray_Descr {
3749
pub type_num: c_int,
3850
}
3951

52+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
53+
pub type PyArray_Descr = PyArray_Descr_fields;
54+
55+
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
56+
#[repr(C)]
57+
pub struct PyArray_Descr {
58+
_data: (),
59+
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
60+
}
61+
4062
#[repr(C)]
4163
pub struct PyArray_DescrProto {
4264
pub ob_base: PyObject,
@@ -76,6 +98,7 @@ pub struct _PyArray_DescrNumPy2 {
7698

7799
#[repr(C)]
78100
struct _PyArray_LegacyDescr {
101+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
79102
pub ob_base: PyObject,
80103
pub typeobj: *mut PyTypeObject,
81104
pub kind: c_char,
@@ -95,9 +118,36 @@ struct _PyArray_LegacyDescr {
95118
pub c_metadata: *mut NpyAuxData,
96119
}
97120

121+
#[allow(non_snake_case)]
122+
#[inline(always)]
123+
pub unsafe fn _PyArray_GET_ITEM_DATA(arr: *const PyArrayObject) -> *mut PyArrayObject_fields {
124+
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
125+
{
126+
PY_ARRAY_API._PyArray_GET_ITEM_DATA(Python::assume_attached(), arr)
127+
}
128+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
129+
{
130+
arr.cast_mut().cast()
131+
}
132+
}
133+
134+
#[allow(non_snake_case)]
135+
#[inline(always)]
136+
pub unsafe fn _PyDataType_GET_ITEM_DATA(dtype: *const PyArray_Descr) -> *mut PyArray_Descr_fields {
137+
#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
138+
{
139+
PY_ARRAY_API._PyDataType_GET_ITEM_DATA(Python::assume_attached(), dtype)
140+
}
141+
#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
142+
{
143+
dtype.cast_mut().cast()
144+
}
145+
}
146+
98147
#[allow(non_snake_case)]
99148
#[inline(always)]
100149
pub unsafe fn PyDataType_ISLEGACY(dtype: *const PyArray_Descr) -> bool {
150+
let dtype = _PyDataType_GET_ITEM_DATA(dtype);
101151
(*dtype).type_num < NPY_TYPES::NPY_VSTRING as _ && (*dtype).type_num >= 0
102152
}
103153

src/strings.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ use pyo3::{
1818
use rustc_hash::FxHashMap;
1919

2020
use crate::dtype::{clone_methods_impl, Element, PyArrayDescr, PyArrayDescrMethods};
21-
use crate::npyffi::PyDataType_SET_ELSIZE;
22-
use crate::npyffi::NPY_TYPES;
21+
use crate::npyffi::{_PyDataType_GET_ITEM_DATA, PyDataType_SET_ELSIZE, NPY_TYPES};
2322

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

192191
let descr = &mut *dtype.as_dtype_ptr();
193192
PyDataType_SET_ELSIZE(py, descr, size.try_into().unwrap());
194-
descr.byteorder = byteorder;
193+
(*_PyDataType_GET_ITEM_DATA(descr)).byteorder = byteorder;
195194

196195
entry.insert(dtype.into())
197196
}

src/untyped_array.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use pyo3::{ffi, pyobject_native_type_named, Bound, PyAny, PyTypeInfo, Python};
88
use crate::array::{PyArray, PyArrayMethods};
99
use crate::cold;
1010
use crate::dtype::PyArrayDescr;
11-
use crate::npyffi;
11+
use crate::npyffi::{self, _PyArray_GET_ITEM_DATA};
1212

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

203203
/// Returns a slice indicating how many bytes to advance when iterating along each axis.
@@ -225,7 +225,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed {
225225
cold();
226226
return &[];
227227
}
228-
let ptr = self.as_array_ptr();
228+
let ptr = unsafe { _PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const()) };
229229
unsafe {
230230
let p = (*ptr).strides;
231231
slice::from_raw_parts(p, n)
@@ -258,7 +258,7 @@ pub trait PyUntypedArrayMethods<'py>: Sealed {
258258
cold();
259259
return &[];
260260
}
261-
let ptr = self.as_array_ptr();
261+
let ptr = unsafe { _PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const()) };
262262
unsafe {
263263
let p = (*ptr).dimensions as *mut usize;
264264
slice::from_raw_parts(p, n)
@@ -283,7 +283,7 @@ mod sealed {
283283
use sealed::Sealed;
284284

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

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

295295
fn dtype(&self) -> Bound<'py, PyArrayDescr> {
296296
unsafe {
297-
let descr_ptr = (*self.as_array_ptr()).descr;
297+
let descr_ptr =
298+
(*npyffi::_PyArray_GET_ITEM_DATA(self.as_array_ptr().cast_const())).descr;
298299
Bound::from_borrowed_ptr(self.py(), descr_ptr.cast()).cast_into_unchecked()
299300
}
300301
}

0 commit comments

Comments
 (0)