numpy/npyffi/
objects.rs

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