Skip to main content

numpy/npyffi/
objects.rs

1//! Low-Level binding for NumPy C API C-objects
2//!
3//! <https://numpy.org/doc/stable/reference/c-api/types-and-structures.html>
4#![allow(non_camel_case_types)]
5
6use libc::FILE;
7use pyo3::ffi::*;
8use std::ffi::*;
9
10use super::types::*;
11use crate::npyffi::*;
12
13pub const NPY_NTYPES_ABI_COMPATIBLE: usize = 21;
14pub const NPY_MAXDIMS_LEGACY_ITERS: usize = 32;
15
16#[repr(C)]
17#[cfg_attr(Py_3_15, repr(align(8)))]
18pub struct PyArrayObject_fields {
19    pub data: *mut c_char,
20    pub nd: c_int,
21    pub dimensions: *mut npy_intp,
22    pub strides: *mut npy_intp,
23    pub base: *mut PyObject,
24    pub descr: *mut PyArray_Descr,
25    pub flags: c_int,
26    pub weakreflist: *mut PyObject,
27}
28
29#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
30opaque_struct!(pub PyArrayObject);
31
32#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
33#[repr(C)]
34pub struct PyArrayObject {
35    pub ob_base: PyObject,
36    pub fields: PyArrayObject_fields,
37}
38
39#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
40#[repr(C)]
41#[cfg_attr(Py_3_15, repr(align(8)))]
42pub struct PyArray_Descr_fields {
43    pub typeobj: *mut PyTypeObject,
44    pub kind: c_char,
45    pub type_: c_char,
46    pub byteorder: c_char,
47    pub _former_flags: c_char,
48    pub type_num: c_int,
49}
50
51#[doc(inline)]
52#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
53pub use _PyArray_DescrNumPy2_fields as PyArray_Descr_fields;
54
55#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
56#[repr(C)]
57pub struct PyArray_Descr {
58    pub ob_base: PyObject,
59    pub fields: PyArray_Descr_fields,
60}
61
62#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
63opaque_struct!(pub PyArray_Descr);
64
65#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
66#[repr(C)]
67pub struct PyArray_DescrProto {
68    pub ob_base: PyObject,
69    pub typeobj: *mut PyTypeObject,
70    pub kind: c_char,
71    pub type_: c_char,
72    pub byteorder: c_char,
73    pub flags: c_char,
74    pub type_num: c_int,
75    pub elsize: c_int,
76    pub alignment: c_int,
77    pub subarray: *mut PyArray_ArrayDescr,
78    pub fields: *mut PyObject,
79    pub names: *mut PyObject,
80    pub f: *mut PyArray_ArrFuncs,
81    pub metadata: *mut PyObject,
82    pub c_metadata: *mut NpyAuxData,
83    pub hash: npy_hash_t,
84}
85
86#[repr(C)]
87#[cfg_attr(Py_3_15, repr(align(8)))]
88pub struct _PyArray_DescrNumPy2_fields {
89    pub typeobj: *mut PyTypeObject,
90    pub kind: c_char,
91    pub type_: c_char,
92    pub byteorder: c_char,
93    pub _former_flags: c_char,
94    pub type_num: c_int,
95    pub flags: npy_uint64,
96    pub elsize: npy_intp,
97    pub alignment: npy_intp,
98    pub metadata: *mut PyObject,
99    pub hash: npy_hash_t,
100    pub reserved_null: [*mut std::ffi::c_void; 2],
101}
102
103#[repr(C)]
104#[cfg_attr(Py_3_15, repr(align(8)))]
105pub(crate) struct _PyArray_LegacyDescr_fields {
106    pub typeobj: *mut PyTypeObject,
107    pub kind: c_char,
108    pub type_: c_char,
109    pub byteorder: c_char,
110    pub _former_flags: c_char,
111    pub type_num: c_int,
112    pub flags: npy_uint64,
113    pub elsize: npy_intp,
114    pub alignment: npy_intp,
115    pub metadata: *mut PyObject,
116    pub hash: npy_hash_t,
117    pub reserved_null: [*mut std::ffi::c_void; 2],
118    pub subarray: *mut PyArray_ArrayDescr,
119    pub fields: *mut PyObject,
120    pub names: *mut PyObject,
121    pub c_metadata: *mut NpyAuxData,
122}
123
124#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
125#[repr(C)]
126pub(crate) struct _PyArray_LegacyDescr {
127    pub _ob_base: PyObject,
128    pub fields: _PyArray_LegacyDescr_fields,
129}
130
131#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
132opaque_struct!(pub(crate) _PyArray_LegacyDescr);
133
134/// # Safety
135/// - attached Python thread-state
136#[allow(non_snake_case)]
137#[inline(always)]
138pub unsafe fn _PyArray_GET_ITEM_DATA(arr: *const PyArrayObject) -> *mut PyArrayObject_fields {
139    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
140    {
141        PY_ARRAY_API._PyArray_GET_ITEM_DATA(Python::assume_attached(), arr)
142    }
143    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
144    {
145        &raw mut (*arr.cast_mut()).fields
146    }
147}
148
149/// # Safety
150/// - attached Python thread-state
151#[allow(non_snake_case)]
152#[inline(always)]
153pub unsafe fn _PyDataType_GET_ITEM_DATA(dtype: *const PyArray_Descr) -> *mut PyArray_Descr_fields {
154    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
155    {
156        PY_ARRAY_API._PyDataType_GET_ITEM_DATA(Python::assume_attached(), dtype)
157    }
158    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
159    {
160        &raw mut (*dtype.cast_mut()).fields
161    }
162}
163
164/// # Safety
165/// - attached Python thread-state
166#[allow(non_snake_case)]
167#[inline(always)]
168unsafe fn _PyArray_LegacyDescr_GET_ITEM_DATA(
169    dtype: *const _PyArray_LegacyDescr,
170) -> *mut _PyArray_LegacyDescr_fields {
171    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
172    {
173        PY_ARRAY_API._PyArray_LegacyDescr_GET_ITEM_DATA(Python::assume_attached(), dtype)
174    }
175    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
176    {
177        &raw mut (*dtype.cast_mut()).fields
178    }
179}
180
181#[allow(non_snake_case)]
182#[inline(always)]
183pub unsafe fn PyDataType_ISLEGACY(dtype: *const PyArray_Descr) -> bool {
184    let dtype = _PyDataType_GET_ITEM_DATA(dtype);
185    (*dtype).type_num < NPY_TYPES::NPY_VSTRING as _ && (*dtype).type_num >= 0
186}
187
188#[allow(non_snake_case)]
189#[inline(always)]
190pub unsafe fn PyDataType_SET_ELSIZE<'py>(
191    py: Python<'py>,
192    dtype: *mut PyArray_Descr,
193    size: npy_intp,
194) {
195    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
196    if is_numpy_2(py) {
197        unsafe {
198            (*_PyDataType_GET_ITEM_DATA(dtype).cast::<_PyArray_DescrNumPy2_fields>()).elsize = size;
199        }
200    } else {
201        // Numpy 1 does not support abi3t, so direct field access is fine
202        unsafe { (*dtype.cast::<PyArray_DescrProto>()).elsize = size as c_int }
203    }
204
205    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
206    unsafe {
207        debug_assert!(is_numpy_2(py));
208        (*_PyDataType_GET_ITEM_DATA(dtype)).elsize = size;
209    }
210}
211
212#[allow(non_snake_case)]
213#[inline(always)]
214pub unsafe fn PyDataType_FLAGS<'py>(py: Python<'py>, dtype: *const PyArray_Descr) -> npy_uint64 {
215    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
216    if is_numpy_2(py) {
217        unsafe { (*_PyDataType_GET_ITEM_DATA(dtype).cast::<_PyArray_DescrNumPy2_fields>()).flags }
218    } else {
219        // Numpy 1 does not support abi3t, so direct field access is fine
220        unsafe { (*dtype.cast::<PyArray_DescrProto>()).flags as c_uchar as npy_uint64 }
221    }
222
223    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
224    unsafe {
225        debug_assert!(is_numpy_2(py));
226        (*_PyDataType_GET_ITEM_DATA(dtype)).flags
227    }
228}
229
230macro_rules! define_descr_accessor {
231    ($name:ident, $property:ident, $type:ty, $legacy_only:literal, $default:expr) => {
232        #[allow(non_snake_case)]
233        #[inline(always)]
234        pub unsafe fn $name<'py>(py: Python<'py>, dtype: *const PyArray_Descr) -> $type {
235            if $legacy_only && !PyDataType_ISLEGACY(dtype) {
236                $default
237            } else {
238                #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
239                if is_numpy_2(py) {
240                    unsafe { (*_PyArray_LegacyDescr_GET_ITEM_DATA(dtype.cast())).$property }
241                } else {
242                    // Numpy 1 does not support abi3t, so direct field access is fine
243                    unsafe { (*dtype.cast::<PyArray_DescrProto>()).$property as $type }
244                }
245
246                #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
247                unsafe {
248                    debug_assert!(is_numpy_2(py));
249                    (*_PyArray_LegacyDescr_GET_ITEM_DATA(dtype.cast())).$property
250                }
251            }
252        }
253    };
254}
255
256define_descr_accessor!(PyDataType_ELSIZE, elsize, npy_intp, false, 0);
257define_descr_accessor!(PyDataType_ALIGNMENT, alignment, npy_intp, false, 0);
258define_descr_accessor!(
259    PyDataType_METADATA,
260    metadata,
261    *mut PyObject,
262    true,
263    std::ptr::null_mut()
264);
265define_descr_accessor!(
266    PyDataType_SUBARRAY,
267    subarray,
268    *mut PyArray_ArrayDescr,
269    true,
270    std::ptr::null_mut()
271);
272define_descr_accessor!(
273    PyDataType_NAMES,
274    names,
275    *mut PyObject,
276    true,
277    std::ptr::null_mut()
278);
279define_descr_accessor!(
280    PyDataType_FIELDS,
281    fields,
282    *mut PyObject,
283    true,
284    std::ptr::null_mut()
285);
286define_descr_accessor!(
287    PyDataType_C_METADATA,
288    c_metadata,
289    *mut NpyAuxData,
290    true,
291    std::ptr::null_mut()
292);
293
294#[repr(C)]
295#[derive(Copy, Clone)]
296pub struct PyArray_ArrayDescr {
297    pub base: *mut PyArray_Descr,
298    pub shape: *mut PyObject,
299}
300
301#[repr(C)]
302#[derive(Copy, Clone)]
303pub struct PyArray_ArrFuncs {
304    pub cast: [PyArray_VectorUnaryFunc; NPY_NTYPES_ABI_COMPATIBLE],
305    pub getitem: PyArray_GetItemFunc,
306    pub setitem: PyArray_SetItemFunc,
307    pub copyswapn: PyArray_CopySwapNFunc,
308    pub copyswap: PyArray_CopySwapFunc,
309    pub compare: PyArray_CompareFunc,
310    pub argmax: PyArray_ArgFunc,
311    pub dotfunc: PyArray_DotFunc,
312    pub scanfunc: PyArray_ScanFunc,
313    pub fromstr: PyArray_FromStrFunc,
314    pub nonzero: PyArray_NonzeroFunc,
315    pub fill: PyArray_FillFunc,
316    pub fillwithscalar: PyArray_FillWithScalarFunc,
317    pub sort: [PyArray_SortFunc; NPY_NSORTS],
318    pub argsort: [PyArray_ArgSortFunc; NPY_NSORTS],
319    pub castdict: *mut PyObject,
320    pub scalarkind: PyArray_ScalarKindFunc,
321    pub cancastscalarkindto: *mut *mut c_int,
322    pub cancastto: *mut c_int,
323    pub _unused1: *mut c_void,
324    pub _unused2: *mut c_void,
325    pub _unused3: *mut c_void,
326    pub argmin: PyArray_ArgFunc,
327}
328
329pub type PyArray_GetItemFunc =
330    Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut PyObject>;
331pub type PyArray_SetItemFunc =
332    Option<unsafe extern "C" fn(*mut PyObject, *mut c_void, *mut c_void) -> c_int>;
333pub type PyArray_CopySwapNFunc = Option<
334    unsafe extern "C" fn(
335        *mut c_void,
336        npy_intp,
337        *mut c_void,
338        npy_intp,
339        npy_intp,
340        c_int,
341        *mut c_void,
342    ),
343>;
344pub type PyArray_CopySwapFunc =
345    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, c_int, *mut c_void)>;
346pub type PyArray_NonzeroFunc = Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> c_uchar>;
347pub type PyArray_CompareFunc =
348    Option<unsafe extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int>;
349pub type PyArray_ArgFunc =
350    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut npy_intp, *mut c_void) -> c_int>;
351pub type PyArray_DotFunc = Option<
352    unsafe extern "C" fn(
353        *mut c_void,
354        npy_intp,
355        *mut c_void,
356        npy_intp,
357        *mut c_void,
358        npy_intp,
359        *mut c_void,
360    ),
361>;
362pub type PyArray_VectorUnaryFunc =
363    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, npy_intp, *mut c_void, *mut c_void)>;
364pub type PyArray_ScanFunc =
365    Option<unsafe extern "C" fn(*mut FILE, *mut c_void, *mut c_char, *mut PyArray_Descr) -> c_int>;
366pub type PyArray_FromStrFunc = Option<
367    unsafe extern "C" fn(*mut c_char, *mut c_void, *mut *mut c_char, *mut PyArray_Descr) -> c_int,
368>;
369pub type PyArray_FillFunc =
370    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void) -> c_int>;
371pub type PyArray_SortFunc =
372    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void) -> c_int>;
373pub type PyArray_ArgSortFunc =
374    Option<unsafe extern "C" fn(*mut c_void, *mut npy_intp, npy_intp, *mut c_void) -> c_int>;
375pub type PyArray_FillWithScalarFunc =
376    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void, *mut c_void) -> c_int>;
377pub type PyArray_ScalarKindFunc = Option<unsafe extern "C" fn(*mut c_void) -> c_int>;
378
379#[repr(C)]
380#[derive(Clone, Copy)]
381pub struct PyArray_Dims {
382    pub ptr: *mut npy_intp,
383    pub len: c_int,
384}
385
386#[repr(C)]
387pub struct PyArray_Chunk {
388    pub ob_base: PyObject,
389    pub base: *mut PyObject,
390    pub ptr: *mut c_void,
391    pub len: npy_intp,
392    pub flags: c_int,
393}
394
395#[repr(C)]
396#[derive(Clone, Copy)]
397pub struct PyArrayInterface {
398    pub two: c_int,
399    pub nd: c_int,
400    pub typekind: c_char,
401    pub itemsize: c_int,
402    pub flags: c_int,
403    pub shape: *mut npy_intp,
404    pub strides: *mut npy_intp,
405    pub data: *mut c_void,
406    pub descr: *mut PyObject,
407}
408
409#[repr(C)]
410#[cfg_attr(Py_3_15, repr(align(8)))]
411pub struct PyUFuncObject_fields {
412    pub nin: c_int,
413    pub nout: c_int,
414    pub nargs: c_int,
415    pub identity: c_int,
416    pub functions: *mut PyUFuncGenericFunction,
417    pub data: *mut *mut c_void,
418    pub ntypes: c_int,
419    pub reserved1: c_int,
420    pub name: *const c_char,
421    pub types: *mut c_char,
422    pub doc: *const c_char,
423    pub ptr: *mut c_void,
424    pub obj: *mut PyObject,
425    pub userloops: *mut PyObject,
426    pub core_enabled: c_int,
427    pub core_num_dim_ix: c_int,
428    pub core_num_dims: *mut c_int,
429    pub core_dim_ixs: *mut c_int,
430    pub core_offsets: *mut c_int,
431    pub core_signature: *mut c_char,
432    pub type_resolver: PyUFunc_TypeResolutionFunc,
433    pub reserved2: *mut c_void, // Was the legacy loop resolver
434    #[cfg(not(Py_LIMITED_API))]
435    pub vectorcall: Option<vectorcallfunc>,
436    #[cfg(Py_LIMITED_API)]
437    pub vectorcall: *mut c_void,
438    pub reserved3: *mut c_void, // Was previously the `PyUFunc_MaskedInnerLoopSelectionFunc`
439    pub op_flags: *mut npy_uint32,
440    pub iter_flags: npy_uint32,
441}
442
443#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
444#[repr(C)]
445pub struct PyUFuncObject {
446    pub ob_base: PyObject,
447    pub fields: PyUFuncObject_fields,
448}
449
450#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
451opaque_struct!(pub PyUFuncObject);
452
453pub type PyUFuncGenericFunction =
454    Option<unsafe extern "C" fn(*mut *mut c_char, *mut npy_intp, *mut npy_intp, *mut c_void)>;
455pub type PyUFunc_MaskedStridedInnerLoopFunc = Option<
456    unsafe extern "C" fn(
457        *mut *mut c_char,
458        *mut npy_intp,
459        *mut c_char,
460        npy_intp,
461        npy_intp,
462        *mut NpyAuxData,
463    ),
464>;
465pub type PyUFunc_TypeResolutionFunc = Option<
466    unsafe extern "C" fn(
467        *mut PyUFuncObject,
468        NPY_CASTING,
469        *mut *mut PyArrayObject,
470        *mut PyObject,
471        *mut *mut PyArray_Descr,
472    ) -> c_int,
473>;
474
475#[repr(C)]
476#[derive(Debug, Copy, Clone)]
477pub struct NpyIter([u8; 0]);
478
479#[repr(C)]
480#[cfg_attr(Py_3_15, repr(align(8)))]
481pub struct PyArrayIterObject_fields {
482    pub nd_m1: c_int,
483    pub index: npy_intp,
484    pub size: npy_intp,
485    pub coordinates: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
486    pub dims_m1: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
487    pub strides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
488    pub backstrides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
489    pub factors: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
490    pub ao: *mut PyArrayObject,
491    pub dataptr: *mut c_char,
492    pub contiguous: npy_bool,
493    pub bounds: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
494    pub limits: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
495    pub limits_sizes: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
496    pub translate: npy_iter_get_dataptr_t,
497}
498
499#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
500#[repr(C)]
501pub struct PyArrayIterObject {
502    pub ob_base: PyObject,
503    pub fields: PyArrayIterObject_fields,
504}
505
506#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
507opaque_struct!(pub PyArrayIterObject);
508
509#[repr(C)]
510#[cfg_attr(Py_3_15, repr(align(8)))]
511pub struct PyArrayMultiIterObject_fields {
512    pub numiter: c_int,
513    pub size: npy_intp,
514    pub index: npy_intp,
515    pub nd: c_int,
516    pub dimensions: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
517    pub iters: [*mut PyArrayIterObject; 32usize],
518}
519
520#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
521#[repr(C)]
522pub struct PyArrayMultiIterObject {
523    pub ob_base: PyObject,
524    pub fields: PyArrayMultiIterObject_fields,
525}
526
527#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
528opaque_struct!(pub PyArrayMultiIterObject);
529
530#[repr(C)]
531#[cfg_attr(Py_3_15, repr(align(8)))]
532pub struct PyArrayNeighborhoodIterObject_fields {
533    pub nd_m1: c_int,
534    pub index: npy_intp,
535    pub size: npy_intp,
536    pub coordinates: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
537    pub dims_m1: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
538    pub strides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
539    pub backstrides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
540    pub factors: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
541    pub ao: *mut PyArrayObject,
542    pub dataptr: *mut c_char,
543    pub contiguous: npy_bool,
544    pub bounds: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
545    pub limits: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
546    pub limits_sizes: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
547    pub translate: npy_iter_get_dataptr_t,
548    pub nd: npy_intp,
549    pub dimensions: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
550    pub _internal_iter: *mut PyArrayIterObject,
551    pub constant: *mut c_char,
552    pub mode: c_int,
553}
554
555#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
556#[repr(C)]
557pub struct PyArrayNeighborhoodIterObject {
558    pub ob_base: PyObject,
559    pub fields: PyArrayNeighborhoodIterObject_fields,
560}
561
562#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
563opaque_struct!(pub PyArrayNeighborhoodIterObject);
564
565pub type NpyIter_IterNextFunc = Option<unsafe extern "C" fn(*mut NpyIter) -> c_int>;
566pub type NpyIter_GetMultiIndexFunc = Option<unsafe extern "C" fn(*mut NpyIter, *mut npy_intp)>;
567pub type PyDataMem_EventHookFunc =
568    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *mut c_void)>;
569pub type npy_iter_get_dataptr_t =
570    Option<unsafe extern "C" fn(*mut PyArrayIterObject, *mut npy_intp) -> *mut c_char>;
571
572#[repr(C)]
573#[derive(Copy, Clone)]
574pub struct NpyAuxData {
575    pub free: NpyAuxData_FreeFunc,
576    pub clone: NpyAuxData_CloneFunc,
577    pub reserved: [*mut c_void; 2usize],
578}
579
580pub type NpyAuxData_FreeFunc = Option<unsafe extern "C" fn(*mut NpyAuxData)>;
581pub type NpyAuxData_CloneFunc = Option<unsafe extern "C" fn(*mut NpyAuxData) -> *mut NpyAuxData>;
582
583#[repr(C)]
584#[derive(Clone, Copy)]
585pub struct PyArray_DatetimeMetaData {
586    pub base: NPY_DATETIMEUNIT,
587    pub num: c_int,
588}
589
590#[repr(C)]
591#[derive(Clone, Copy)]
592pub struct PyArray_DatetimeDTypeMetaData {
593    pub base: NpyAuxData,
594    pub meta: PyArray_DatetimeMetaData,
595}
596
597// npy_packed_static_string and npy_string_allocator are opaque pointers.
598// FIXME(adamreichold): Consider extern types when they are stabilized.
599// https://github.com/rust-lang/rust/issues/43467
600#[repr(C)]
601pub struct npy_packed_static_string([u8; 0]);
602
603#[repr(C)]
604pub struct npy_string_allocator([u8; 0]);
605
606#[cfg(not(Py_LIMITED_API))]
607#[repr(C)]
608pub struct PyArray_DTypeMeta {
609    pub superclass: PyHeapTypeObject,
610    pub singleton: *mut PyArray_Descr,
611    pub type_num: c_int,
612    pub scalar_type: *mut PyTypeObject,
613    pub flags: npy_uint64,
614    pub dt_slots: *mut c_void,
615    pub reserved: [*mut c_void; 3],
616}
617
618#[cfg(Py_LIMITED_API)]
619pub type PyArray_DTypeMeta = PyTypeObject;
620
621#[repr(C)]
622#[derive(Clone, Copy)]
623pub struct npy_static_string {
624    pub size: usize,
625    pub buf: *const c_char,
626}
627
628#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
629#[repr(C)]
630pub struct PyArray_StringDTypeObject {
631    pub base: PyArray_Descr,
632    pub na_object: *mut PyObject,
633    pub coerce: c_char,
634    pub has_nan_na: c_char,
635    pub has_string_na: c_char,
636    pub array_owned: c_char,
637    pub default_string: npy_static_string,
638    pub na_name: npy_static_string,
639    pub allocator: *mut npy_string_allocator,
640}
641
642#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
643opaque_struct!(pub PyArray_StringDTypeObject);
644
645#[repr(C)]
646#[derive(Clone, Copy)]
647pub struct PyArrayMethod_Spec {
648    pub name: *const c_char,
649    pub nin: c_int,
650    pub nout: c_int,
651    pub casting: NPY_CASTING,
652    pub flags: NPY_ARRAYMETHOD_FLAGS,
653    pub dtypes: *mut *mut PyArray_DTypeMeta,
654    pub slots: *mut PyType_Slot,
655}
656
657#[repr(C)]
658#[derive(Clone, Copy)]
659pub struct PyArrayDTypeMeta_Spec {
660    pub typeobj: *mut PyTypeObject,
661    pub flags: c_int,
662    pub casts: *mut *mut PyArrayMethod_Spec,
663    pub slots: *mut PyType_Slot,
664    pub baseclass: *mut PyTypeObject,
665}