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    unsafe {
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    unsafe {
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    unsafe {
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    unsafe {
185        let dtype = _PyDataType_GET_ITEM_DATA(dtype);
186        (*dtype).type_num < NPY_TYPES::NPY_VSTRING as _ && (*dtype).type_num >= 0
187    }
188}
189
190#[allow(non_snake_case)]
191#[inline(always)]
192pub unsafe fn PyDataType_SET_ELSIZE<'py>(
193    py: Python<'py>,
194    dtype: *mut PyArray_Descr,
195    size: npy_intp,
196) {
197    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
198    if is_numpy_2(py) {
199        unsafe {
200            (*_PyDataType_GET_ITEM_DATA(dtype).cast::<_PyArray_DescrNumPy2_fields>()).elsize = size;
201        }
202    } else {
203        // Numpy 1 does not support abi3t, so direct field access is fine
204        unsafe { (*dtype.cast::<PyArray_DescrProto>()).elsize = size as c_int }
205    }
206
207    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
208    unsafe {
209        debug_assert!(is_numpy_2(py));
210        (*_PyDataType_GET_ITEM_DATA(dtype)).elsize = size;
211    }
212}
213
214#[allow(non_snake_case)]
215#[inline(always)]
216pub unsafe fn PyDataType_FLAGS<'py>(py: Python<'py>, dtype: *const PyArray_Descr) -> npy_uint64 {
217    #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
218    if is_numpy_2(py) {
219        unsafe { (*_PyDataType_GET_ITEM_DATA(dtype).cast::<_PyArray_DescrNumPy2_fields>()).flags }
220    } else {
221        // Numpy 1 does not support abi3t, so direct field access is fine
222        unsafe { (*dtype.cast::<PyArray_DescrProto>()).flags as c_uchar as npy_uint64 }
223    }
224
225    #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
226    unsafe {
227        debug_assert!(is_numpy_2(py));
228        (*_PyDataType_GET_ITEM_DATA(dtype)).flags
229    }
230}
231
232macro_rules! define_descr_accessor {
233    ($name:ident, $property:ident, $type:ty, $legacy_only:literal, $default:expr) => {
234        #[allow(non_snake_case)]
235        #[inline(always)]
236        pub unsafe fn $name<'py>(py: Python<'py>, dtype: *const PyArray_Descr) -> $type {
237            if $legacy_only && unsafe { !PyDataType_ISLEGACY(dtype) } {
238                $default
239            } else {
240                #[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
241                if is_numpy_2(py) {
242                    unsafe { (*_PyArray_LegacyDescr_GET_ITEM_DATA(dtype.cast())).$property }
243                } else {
244                    // Numpy 1 does not support abi3t, so direct field access is fine
245                    unsafe { (*dtype.cast::<PyArray_DescrProto>()).$property as $type }
246                }
247
248                #[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
249                unsafe {
250                    debug_assert!(is_numpy_2(py));
251                    (*_PyArray_LegacyDescr_GET_ITEM_DATA(dtype.cast())).$property
252                }
253            }
254        }
255    };
256}
257
258define_descr_accessor!(PyDataType_ELSIZE, elsize, npy_intp, false, 0);
259define_descr_accessor!(PyDataType_ALIGNMENT, alignment, npy_intp, false, 0);
260define_descr_accessor!(
261    PyDataType_METADATA,
262    metadata,
263    *mut PyObject,
264    true,
265    std::ptr::null_mut()
266);
267define_descr_accessor!(
268    PyDataType_SUBARRAY,
269    subarray,
270    *mut PyArray_ArrayDescr,
271    true,
272    std::ptr::null_mut()
273);
274define_descr_accessor!(
275    PyDataType_NAMES,
276    names,
277    *mut PyObject,
278    true,
279    std::ptr::null_mut()
280);
281define_descr_accessor!(
282    PyDataType_FIELDS,
283    fields,
284    *mut PyObject,
285    true,
286    std::ptr::null_mut()
287);
288define_descr_accessor!(
289    PyDataType_C_METADATA,
290    c_metadata,
291    *mut NpyAuxData,
292    true,
293    std::ptr::null_mut()
294);
295
296#[repr(C)]
297#[derive(Copy, Clone)]
298pub struct PyArray_ArrayDescr {
299    pub base: *mut PyArray_Descr,
300    pub shape: *mut PyObject,
301}
302
303#[repr(C)]
304#[derive(Copy, Clone)]
305pub struct PyArray_ArrFuncs {
306    pub cast: [PyArray_VectorUnaryFunc; NPY_NTYPES_ABI_COMPATIBLE],
307    pub getitem: PyArray_GetItemFunc,
308    pub setitem: PyArray_SetItemFunc,
309    pub copyswapn: PyArray_CopySwapNFunc,
310    pub copyswap: PyArray_CopySwapFunc,
311    pub compare: PyArray_CompareFunc,
312    pub argmax: PyArray_ArgFunc,
313    pub dotfunc: PyArray_DotFunc,
314    pub scanfunc: PyArray_ScanFunc,
315    pub fromstr: PyArray_FromStrFunc,
316    pub nonzero: PyArray_NonzeroFunc,
317    pub fill: PyArray_FillFunc,
318    pub fillwithscalar: PyArray_FillWithScalarFunc,
319    pub sort: [PyArray_SortFunc; NPY_NSORTS],
320    pub argsort: [PyArray_ArgSortFunc; NPY_NSORTS],
321    pub castdict: *mut PyObject,
322    pub scalarkind: PyArray_ScalarKindFunc,
323    pub cancastscalarkindto: *mut *mut c_int,
324    pub cancastto: *mut c_int,
325    pub _unused1: *mut c_void,
326    pub _unused2: *mut c_void,
327    pub _unused3: *mut c_void,
328    pub argmin: PyArray_ArgFunc,
329}
330
331pub type PyArray_GetItemFunc =
332    Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> *mut PyObject>;
333pub type PyArray_SetItemFunc =
334    Option<unsafe extern "C" fn(*mut PyObject, *mut c_void, *mut c_void) -> c_int>;
335pub type PyArray_CopySwapNFunc = Option<
336    unsafe extern "C" fn(
337        *mut c_void,
338        npy_intp,
339        *mut c_void,
340        npy_intp,
341        npy_intp,
342        c_int,
343        *mut c_void,
344    ),
345>;
346pub type PyArray_CopySwapFunc =
347    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, c_int, *mut c_void)>;
348pub type PyArray_NonzeroFunc = Option<unsafe extern "C" fn(*mut c_void, *mut c_void) -> c_uchar>;
349pub type PyArray_CompareFunc =
350    Option<unsafe extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int>;
351pub type PyArray_ArgFunc =
352    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut npy_intp, *mut c_void) -> c_int>;
353pub type PyArray_DotFunc = Option<
354    unsafe extern "C" fn(
355        *mut c_void,
356        npy_intp,
357        *mut c_void,
358        npy_intp,
359        *mut c_void,
360        npy_intp,
361        *mut c_void,
362    ),
363>;
364pub type PyArray_VectorUnaryFunc =
365    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, npy_intp, *mut c_void, *mut c_void)>;
366pub type PyArray_ScanFunc =
367    Option<unsafe extern "C" fn(*mut FILE, *mut c_void, *mut c_char, *mut PyArray_Descr) -> c_int>;
368pub type PyArray_FromStrFunc = Option<
369    unsafe extern "C" fn(*mut c_char, *mut c_void, *mut *mut c_char, *mut PyArray_Descr) -> c_int,
370>;
371pub type PyArray_FillFunc =
372    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void) -> c_int>;
373pub type PyArray_SortFunc =
374    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void) -> c_int>;
375pub type PyArray_ArgSortFunc =
376    Option<unsafe extern "C" fn(*mut c_void, *mut npy_intp, npy_intp, *mut c_void) -> c_int>;
377pub type PyArray_FillWithScalarFunc =
378    Option<unsafe extern "C" fn(*mut c_void, npy_intp, *mut c_void, *mut c_void) -> c_int>;
379pub type PyArray_ScalarKindFunc = Option<unsafe extern "C" fn(*mut c_void) -> c_int>;
380
381#[repr(C)]
382#[derive(Clone, Copy)]
383pub struct PyArray_Dims {
384    pub ptr: *mut npy_intp,
385    pub len: c_int,
386}
387
388#[repr(C)]
389pub struct PyArray_Chunk {
390    pub ob_base: PyObject,
391    pub base: *mut PyObject,
392    pub ptr: *mut c_void,
393    pub len: npy_intp,
394    pub flags: c_int,
395}
396
397#[repr(C)]
398#[derive(Clone, Copy)]
399pub struct PyArrayInterface {
400    pub two: c_int,
401    pub nd: c_int,
402    pub typekind: c_char,
403    pub itemsize: c_int,
404    pub flags: c_int,
405    pub shape: *mut npy_intp,
406    pub strides: *mut npy_intp,
407    pub data: *mut c_void,
408    pub descr: *mut PyObject,
409}
410
411#[repr(C)]
412#[cfg_attr(Py_3_15, repr(align(8)))]
413pub struct PyUFuncObject_fields {
414    pub nin: c_int,
415    pub nout: c_int,
416    pub nargs: c_int,
417    pub identity: c_int,
418    pub functions: *mut PyUFuncGenericFunction,
419    pub data: *mut *mut c_void,
420    pub ntypes: c_int,
421    pub reserved1: c_int,
422    pub name: *const c_char,
423    pub types: *mut c_char,
424    pub doc: *const c_char,
425    pub ptr: *mut c_void,
426    pub obj: *mut PyObject,
427    pub userloops: *mut PyObject,
428    pub core_enabled: c_int,
429    pub core_num_dim_ix: c_int,
430    pub core_num_dims: *mut c_int,
431    pub core_dim_ixs: *mut c_int,
432    pub core_offsets: *mut c_int,
433    pub core_signature: *mut c_char,
434    pub type_resolver: PyUFunc_TypeResolutionFunc,
435    pub reserved2: *mut c_void, // Was the legacy loop resolver
436    #[cfg(not(Py_LIMITED_API))]
437    pub vectorcall: Option<vectorcallfunc>,
438    #[cfg(Py_LIMITED_API)]
439    pub vectorcall: *mut c_void,
440    pub reserved3: *mut c_void, // Was previously the `PyUFunc_MaskedInnerLoopSelectionFunc`
441    pub op_flags: *mut npy_uint32,
442    pub iter_flags: npy_uint32,
443}
444
445#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
446#[repr(C)]
447pub struct PyUFuncObject {
448    pub ob_base: PyObject,
449    pub fields: PyUFuncObject_fields,
450}
451
452#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
453opaque_struct!(pub PyUFuncObject);
454
455pub type PyUFuncGenericFunction =
456    Option<unsafe extern "C" fn(*mut *mut c_char, *mut npy_intp, *mut npy_intp, *mut c_void)>;
457pub type PyUFunc_MaskedStridedInnerLoopFunc = Option<
458    unsafe extern "C" fn(
459        *mut *mut c_char,
460        *mut npy_intp,
461        *mut c_char,
462        npy_intp,
463        npy_intp,
464        *mut NpyAuxData,
465    ),
466>;
467pub type PyUFunc_TypeResolutionFunc = Option<
468    unsafe extern "C" fn(
469        *mut PyUFuncObject,
470        NPY_CASTING,
471        *mut *mut PyArrayObject,
472        *mut PyObject,
473        *mut *mut PyArray_Descr,
474    ) -> c_int,
475>;
476
477#[repr(C)]
478#[derive(Debug, Copy, Clone)]
479pub struct NpyIter([u8; 0]);
480
481#[repr(C)]
482#[cfg_attr(Py_3_15, repr(align(8)))]
483pub struct PyArrayIterObject_fields {
484    pub nd_m1: c_int,
485    pub index: npy_intp,
486    pub size: npy_intp,
487    pub coordinates: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
488    pub dims_m1: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
489    pub strides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
490    pub backstrides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
491    pub factors: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
492    pub ao: *mut PyArrayObject,
493    pub dataptr: *mut c_char,
494    pub contiguous: npy_bool,
495    pub bounds: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
496    pub limits: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
497    pub limits_sizes: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
498    pub translate: npy_iter_get_dataptr_t,
499}
500
501#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
502#[repr(C)]
503pub struct PyArrayIterObject {
504    pub ob_base: PyObject,
505    pub fields: PyArrayIterObject_fields,
506}
507
508#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
509opaque_struct!(pub PyArrayIterObject);
510
511#[repr(C)]
512#[cfg_attr(Py_3_15, repr(align(8)))]
513pub struct PyArrayMultiIterObject_fields {
514    pub numiter: c_int,
515    pub size: npy_intp,
516    pub index: npy_intp,
517    pub nd: c_int,
518    pub dimensions: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
519    pub iters: [*mut PyArrayIterObject; 32usize],
520}
521
522#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
523#[repr(C)]
524pub struct PyArrayMultiIterObject {
525    pub ob_base: PyObject,
526    pub fields: PyArrayMultiIterObject_fields,
527}
528
529#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
530opaque_struct!(pub PyArrayMultiIterObject);
531
532#[repr(C)]
533#[cfg_attr(Py_3_15, repr(align(8)))]
534pub struct PyArrayNeighborhoodIterObject_fields {
535    pub nd_m1: c_int,
536    pub index: npy_intp,
537    pub size: npy_intp,
538    pub coordinates: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
539    pub dims_m1: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
540    pub strides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
541    pub backstrides: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
542    pub factors: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
543    pub ao: *mut PyArrayObject,
544    pub dataptr: *mut c_char,
545    pub contiguous: npy_bool,
546    pub bounds: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
547    pub limits: [[npy_intp; 2usize]; NPY_MAXDIMS_LEGACY_ITERS],
548    pub limits_sizes: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
549    pub translate: npy_iter_get_dataptr_t,
550    pub nd: npy_intp,
551    pub dimensions: [npy_intp; NPY_MAXDIMS_LEGACY_ITERS],
552    pub _internal_iter: *mut PyArrayIterObject,
553    pub constant: *mut c_char,
554    pub mode: c_int,
555}
556
557#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
558#[repr(C)]
559pub struct PyArrayNeighborhoodIterObject {
560    pub ob_base: PyObject,
561    pub fields: PyArrayNeighborhoodIterObject_fields,
562}
563
564#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
565opaque_struct!(pub PyArrayNeighborhoodIterObject);
566
567pub type NpyIter_IterNextFunc = Option<unsafe extern "C" fn(*mut NpyIter) -> c_int>;
568pub type NpyIter_GetMultiIndexFunc = Option<unsafe extern "C" fn(*mut NpyIter, *mut npy_intp)>;
569pub type PyDataMem_EventHookFunc =
570    Option<unsafe extern "C" fn(*mut c_void, *mut c_void, usize, *mut c_void)>;
571pub type npy_iter_get_dataptr_t =
572    Option<unsafe extern "C" fn(*mut PyArrayIterObject, *mut npy_intp) -> *mut c_char>;
573
574#[repr(C)]
575#[derive(Copy, Clone)]
576pub struct NpyAuxData {
577    pub free: NpyAuxData_FreeFunc,
578    pub clone: NpyAuxData_CloneFunc,
579    pub reserved: [*mut c_void; 2usize],
580}
581
582pub type NpyAuxData_FreeFunc = Option<unsafe extern "C" fn(*mut NpyAuxData)>;
583pub type NpyAuxData_CloneFunc = Option<unsafe extern "C" fn(*mut NpyAuxData) -> *mut NpyAuxData>;
584
585#[repr(C)]
586#[derive(Clone, Copy)]
587pub struct PyArray_DatetimeMetaData {
588    pub base: NPY_DATETIMEUNIT,
589    pub num: c_int,
590}
591
592#[repr(C)]
593#[derive(Clone, Copy)]
594pub struct PyArray_DatetimeDTypeMetaData {
595    pub base: NpyAuxData,
596    pub meta: PyArray_DatetimeMetaData,
597}
598
599// npy_packed_static_string and npy_string_allocator are opaque pointers.
600// FIXME(adamreichold): Consider extern types when they are stabilized.
601// https://github.com/rust-lang/rust/issues/43467
602#[repr(C)]
603pub struct npy_packed_static_string([u8; 0]);
604
605#[repr(C)]
606pub struct npy_string_allocator([u8; 0]);
607
608#[cfg(not(Py_LIMITED_API))]
609#[repr(C)]
610pub struct PyArray_DTypeMeta {
611    pub superclass: PyHeapTypeObject,
612    pub singleton: *mut PyArray_Descr,
613    pub type_num: c_int,
614    pub scalar_type: *mut PyTypeObject,
615    pub flags: npy_uint64,
616    pub dt_slots: *mut c_void,
617    pub reserved: [*mut c_void; 3],
618}
619
620#[cfg(Py_LIMITED_API)]
621pub type PyArray_DTypeMeta = PyTypeObject;
622
623#[repr(C)]
624#[derive(Clone, Copy)]
625pub struct npy_static_string {
626    pub size: usize,
627    pub buf: *const c_char,
628}
629
630#[cfg(not(all(Py_LIMITED_API, Py_GIL_DISABLED)))]
631#[repr(C)]
632pub struct PyArray_StringDTypeObject {
633    pub base: PyArray_Descr,
634    pub na_object: *mut PyObject,
635    pub coerce: c_char,
636    pub has_nan_na: c_char,
637    pub has_string_na: c_char,
638    pub array_owned: c_char,
639    pub default_string: npy_static_string,
640    pub na_name: npy_static_string,
641    pub allocator: *mut npy_string_allocator,
642}
643
644#[cfg(all(Py_LIMITED_API, Py_GIL_DISABLED))]
645opaque_struct!(pub PyArray_StringDTypeObject);
646
647#[repr(C)]
648#[derive(Clone, Copy)]
649pub struct PyArrayMethod_Spec {
650    pub name: *const c_char,
651    pub nin: c_int,
652    pub nout: c_int,
653    pub casting: NPY_CASTING,
654    pub flags: NPY_ARRAYMETHOD_FLAGS,
655    pub dtypes: *mut *mut PyArray_DTypeMeta,
656    pub slots: *mut PyType_Slot,
657}
658
659#[repr(C)]
660#[derive(Clone, Copy)]
661pub struct PyArrayDTypeMeta_Spec {
662    pub typeobj: *mut PyTypeObject,
663    pub flags: c_int,
664    pub casts: *mut *mut PyArrayMethod_Spec,
665    pub slots: *mut PyType_Slot,
666    pub baseclass: *mut PyTypeObject,
667}