numpy/npyffi/
array.rs

1//! Low-Level binding for [Array API](https://numpy.org/doc/stable/reference/c-api/array.html)
2//!
3//! Note that NumPy's low-level allocation functions `PyArray_{malloc,realloc,free}` are not part of this module.
4//! The reason is that they would be re-exports of the `PyMem_Raw{Malloc,Realloc,Free}` functions from PyO3,
5//! but those are not unconditionally exported, i.e. they are not available when using the limited Python C-API.
6
7use std::os::raw::*;
8
9use libc::FILE;
10use pyo3::{
11    ffi::{self, PyObject, PyTypeObject},
12    sync::GILOnceCell,
13};
14
15use crate::npyffi::*;
16
17pub(crate) fn numpy_core_name(py: Python<'_>) -> PyResult<&'static str> {
18    static MOD_NAME: GILOnceCell<&'static str> = GILOnceCell::new();
19
20    MOD_NAME
21        .get_or_try_init(py, || {
22            // numpy 2 renamed to numpy._core
23
24            // strategy mirrored from https://github.com/pybind/pybind11/blob/af67e87393b0f867ccffc2702885eea12de063fc/include/pybind11/numpy.h#L175-L195
25
26            let numpy = PyModule::import(py, "numpy")?;
27            let version_string = numpy.getattr("__version__")?;
28
29            let numpy_lib = PyModule::import(py, "numpy.lib")?;
30            let numpy_version = numpy_lib
31                .getattr("NumpyVersion")?
32                .call1((version_string,))?;
33            let major_version: u8 = numpy_version.getattr("major")?.extract()?;
34
35            Ok(if major_version >= 2 {
36                "numpy._core"
37            } else {
38                "numpy.core"
39            })
40        })
41        .copied()
42}
43
44pub(crate) fn mod_name(py: Python<'_>) -> PyResult<&'static str> {
45    static MOD_NAME: GILOnceCell<String> = GILOnceCell::new();
46    MOD_NAME
47        .get_or_try_init(py, || {
48            let numpy_core = numpy_core_name(py)?;
49            Ok(format!("{}.multiarray", numpy_core))
50        })
51        .map(String::as_str)
52}
53
54const CAPSULE_NAME: &str = "_ARRAY_API";
55
56/// A global variable which stores a ['capsule'](https://docs.python.org/3/c-api/capsule.html)
57/// pointer to [Numpy Array API](https://numpy.org/doc/stable/reference/c-api/array.html).
58///
59/// You can access raw C APIs via this variable.
60///
61/// See [PyArrayAPI](struct.PyArrayAPI.html) for what methods you can use via this variable.
62///
63/// # Example
64/// ```
65/// use numpy::prelude::*;
66/// use numpy::{PyArray, npyffi::types::NPY_SORTKIND, PY_ARRAY_API};
67/// pyo3::Python::with_gil(|py| {
68///     let array = PyArray::from_slice(py, &[3, 2, 4]);
69///     unsafe {
70///         PY_ARRAY_API.PyArray_Sort(py, array.as_array_ptr(), 0, NPY_SORTKIND::NPY_QUICKSORT);
71///     }
72///     assert_eq!(array.readonly().as_slice().unwrap(), &[2, 3, 4]);
73/// })
74/// ```
75pub static PY_ARRAY_API: PyArrayAPI = PyArrayAPI(GILOnceCell::new());
76
77/// See [PY_ARRAY_API] for more.
78pub struct PyArrayAPI(GILOnceCell<*const *const c_void>);
79
80unsafe impl Send for PyArrayAPI {}
81
82unsafe impl Sync for PyArrayAPI {}
83
84impl PyArrayAPI {
85    unsafe fn get<'py>(&self, py: Python<'py>, offset: isize) -> *const *const c_void {
86        let api = self
87            .0
88            .get_or_try_init(py, || get_numpy_api(py, mod_name(py)?, CAPSULE_NAME))
89            .expect("Failed to access NumPy array API capsule");
90
91        api.offset(offset)
92    }
93}
94
95impl PyArrayAPI {
96    impl_api![0; PyArray_GetNDArrayCVersion() -> c_uint];
97    impl_api![40; PyArray_SetNumericOps(dict: *mut PyObject) -> c_int];
98    impl_api![41; PyArray_GetNumericOps() -> *mut PyObject];
99    impl_api![42; PyArray_INCREF(mp: *mut PyArrayObject) -> c_int];
100    impl_api![43; PyArray_XDECREF(mp: *mut PyArrayObject) -> c_int];
101    impl_api![44; PyArray_SetStringFunction(op: *mut PyObject, repr: c_int)];
102    impl_api![45; PyArray_DescrFromType(type_: c_int) -> *mut PyArray_Descr];
103    impl_api![46; PyArray_TypeObjectFromType(type_: c_int) -> *mut PyObject];
104    impl_api![47; PyArray_Zero(arr: *mut PyArrayObject) -> *mut c_char];
105    impl_api![48; PyArray_One(arr: *mut PyArrayObject) -> *mut c_char];
106    impl_api![49; PyArray_CastToType(arr: *mut PyArrayObject, dtype: *mut PyArray_Descr, is_f_order: c_int) -> *mut PyObject];
107    impl_api![50; NumPy1; PyArray_CastTo(out: *mut PyArrayObject, mp: *mut PyArrayObject) -> c_int];
108    impl_api![52; PyArray_CanCastSafely(fromtype: c_int, totype: c_int) -> c_int];
109    impl_api![53; PyArray_CanCastTo(from: *mut PyArray_Descr, to: *mut PyArray_Descr) -> npy_bool];
110    impl_api![54; PyArray_ObjectType(op: *mut PyObject, minimum_type: c_int) -> c_int];
111    impl_api![55; PyArray_DescrFromObject(op: *mut PyObject, mintype: *mut PyArray_Descr) -> *mut PyArray_Descr];
112    impl_api![56; PyArray_ConvertToCommonType(op: *mut PyObject, retn: *mut c_int) -> *mut *mut PyArrayObject];
113    impl_api![57; PyArray_DescrFromScalar(sc: *mut PyObject) -> *mut PyArray_Descr];
114    impl_api![58; PyArray_DescrFromTypeObject(type_: *mut PyObject) -> *mut PyArray_Descr];
115    impl_api![59; PyArray_Size(op: *mut PyObject) -> npy_intp];
116    impl_api![60; PyArray_Scalar(data: *mut c_void, descr: *mut PyArray_Descr, base: *mut PyObject) -> *mut PyObject];
117    impl_api![61; PyArray_FromScalar(scalar: *mut PyObject, outcode: *mut PyArray_Descr) -> *mut PyObject];
118    impl_api![62; PyArray_ScalarAsCtype(scalar: *mut PyObject, ctypeptr: *mut c_void)];
119    impl_api![63; PyArray_CastScalarToCtype(scalar: *mut PyObject, ctypeptr: *mut c_void, outcode: *mut PyArray_Descr) -> c_int];
120    impl_api![64; PyArray_CastScalarDirect(scalar: *mut PyObject, indescr: *mut PyArray_Descr, ctypeptr: *mut c_void, outtype: c_int) -> c_int];
121    impl_api![65; NumPy1; PyArray_ScalarFromObject(object: *mut PyObject) -> *mut PyObject];
122    impl_api![65; NumPy2; PyArray_Pack(descr: *mut PyArray_Descr, item: *mut c_void, value: *const PyObject) -> *mut PyObject];
123    impl_api![66; NumPy1; PyArray_GetCastFunc(descr: *mut PyArray_Descr, type_num: c_int) -> PyArray_VectorUnaryFunc];
124    impl_api![67; NumPy1; PyArray_FromDims(nd: c_int, d: *mut c_int, type_: c_int) -> *mut PyObject];
125    impl_api![68; NumPy1; PyArray_FromDimsAndDataAndDescr(nd: c_int, d: *mut c_int, descr: *mut PyArray_Descr, data: *mut c_char) -> *mut PyObject];
126    impl_api![69; PyArray_FromAny(op: *mut PyObject, newtype: *mut PyArray_Descr, min_depth: c_int, max_depth: c_int, flags: c_int, context: *mut PyObject) -> *mut PyObject];
127    impl_api![70; PyArray_EnsureArray(op: *mut PyObject) -> *mut PyObject];
128    impl_api![71; PyArray_EnsureAnyArray(op: *mut PyObject) -> *mut PyObject];
129    impl_api![72; PyArray_FromFile(fp: *mut FILE, dtype: *mut PyArray_Descr, num: npy_intp, sep: *mut c_char) -> *mut PyObject];
130    impl_api![73; PyArray_FromString(data: *mut c_char, slen: npy_intp, dtype: *mut PyArray_Descr, num: npy_intp, sep: *mut c_char) -> *mut PyObject];
131    impl_api![74; PyArray_FromBuffer(buf: *mut PyObject, type_: *mut PyArray_Descr, count: npy_intp, offset: npy_intp) -> *mut PyObject];
132    impl_api![75; PyArray_FromIter(obj: *mut PyObject, dtype: *mut PyArray_Descr, count: npy_intp) -> *mut PyObject];
133    impl_api![76; PyArray_Return(mp: *mut PyArrayObject) -> *mut PyObject];
134    impl_api![77; PyArray_GetField(self_: *mut PyArrayObject, typed: *mut PyArray_Descr, offset: c_int) -> *mut PyObject];
135    impl_api![78; PyArray_SetField(self_: *mut PyArrayObject, dtype: *mut PyArray_Descr, offset: c_int, val: *mut PyObject) -> c_int];
136    impl_api![79; PyArray_Byteswap(self_: *mut PyArrayObject, inplace: npy_bool) -> *mut PyObject];
137    impl_api![80; PyArray_Resize(self_: *mut PyArrayObject, newshape: *mut PyArray_Dims, refcheck: c_int, order: NPY_ORDER) -> *mut PyObject];
138    impl_api![81; NumPy1; PyArray_MoveInto(dst: *mut PyArrayObject, src: *mut PyArrayObject) -> c_int];
139    impl_api![84; PyArray_CopyObject(dest: *mut PyArrayObject, src_object: *mut PyObject) -> c_int];
140    impl_api![85; PyArray_NewCopy(obj: *mut PyArrayObject, order: NPY_ORDER) -> *mut PyObject];
141    impl_api![86; PyArray_ToList(self_: *mut PyArrayObject) -> *mut PyObject];
142    impl_api![87; PyArray_ToString(self_: *mut PyArrayObject, order: NPY_ORDER) -> *mut PyObject];
143    impl_api![88; PyArray_ToFile(self_: *mut PyArrayObject, fp: *mut FILE, sep: *mut c_char, format: *mut c_char) -> c_int];
144    impl_api![89; PyArray_Dump(self_: *mut PyObject, file: *mut PyObject, protocol: c_int) -> c_int];
145    impl_api![90; PyArray_Dumps(self_: *mut PyObject, protocol: c_int) -> *mut PyObject];
146    impl_api![91; PyArray_ValidType(type_: c_int) -> c_int];
147    impl_api![92; PyArray_UpdateFlags(ret: *mut PyArrayObject, flagmask: c_int)];
148    impl_api![93; PyArray_New(subtype: *mut PyTypeObject, nd: c_int, dims: *mut npy_intp, type_num: c_int, strides: *mut npy_intp, data: *mut c_void, itemsize: c_int, flags: c_int, obj: *mut PyObject) -> *mut PyObject];
149    impl_api![94; PyArray_NewFromDescr(subtype: *mut PyTypeObject, descr: *mut PyArray_Descr, nd: c_int, dims: *mut npy_intp, strides: *mut npy_intp, data: *mut c_void, flags: c_int, obj: *mut PyObject) -> *mut PyObject];
150    impl_api![95; PyArray_DescrNew(base: *mut PyArray_Descr) -> *mut PyArray_Descr];
151    impl_api![96; PyArray_DescrNewFromType(type_num: c_int) -> *mut PyArray_Descr];
152    impl_api![97; PyArray_GetPriority(obj: *mut PyObject, default_: f64) -> f64];
153    impl_api![98; PyArray_IterNew(obj: *mut PyObject) -> *mut PyObject];
154    // impl_api![99; PyArray_MultiIterNew(n: c_int, ...) -> *mut PyObject];
155    impl_api![100; PyArray_PyIntAsInt(o: *mut PyObject) -> c_int];
156    impl_api![101; PyArray_PyIntAsIntp(o: *mut PyObject) -> npy_intp];
157    impl_api![102; PyArray_Broadcast(mit: *mut PyArrayMultiIterObject) -> c_int];
158    impl_api![103; NumPy1; PyArray_FillObjectArray(arr: *mut PyArrayObject, obj: *mut PyObject)];
159    impl_api![104; PyArray_FillWithScalar(arr: *mut PyArrayObject, obj: *mut PyObject) -> c_int];
160    impl_api![105; PyArray_CheckStrides(elsize: c_int, nd: c_int, numbytes: npy_intp, offset: npy_intp, dims: *mut npy_intp, newstrides: *mut npy_intp) -> npy_bool];
161    impl_api![106; PyArray_DescrNewByteorder(self_: *mut PyArray_Descr, newendian: c_char) -> *mut PyArray_Descr];
162    impl_api![107; PyArray_IterAllButAxis(obj: *mut PyObject, inaxis: *mut c_int) -> *mut PyObject];
163    impl_api![108; PyArray_CheckFromAny(op: *mut PyObject, descr: *mut PyArray_Descr, min_depth: c_int, max_depth: c_int, requires: c_int, context: *mut PyObject) -> *mut PyObject];
164    impl_api![109; PyArray_FromArray(arr: *mut PyArrayObject, newtype: *mut PyArray_Descr, flags: c_int) -> *mut PyObject];
165    impl_api![110; PyArray_FromInterface(origin: *mut PyObject) -> *mut PyObject];
166    impl_api![111; PyArray_FromStructInterface(input: *mut PyObject) -> *mut PyObject];
167    impl_api![112; PyArray_FromArrayAttr(op: *mut PyObject, typecode: *mut PyArray_Descr, context: *mut PyObject) -> *mut PyObject];
168    impl_api![113; PyArray_ScalarKind(typenum: c_int, arr: *mut *mut PyArrayObject) -> NPY_SCALARKIND];
169    impl_api![114; PyArray_CanCoerceScalar(thistype: c_int, neededtype: c_int, scalar: NPY_SCALARKIND) -> c_int];
170    impl_api![115; NumPy1; PyArray_NewFlagsObject(obj: *mut PyObject) -> *mut PyObject];
171    impl_api![116; PyArray_CanCastScalar(from: *mut PyTypeObject, to: *mut PyTypeObject) -> npy_bool];
172    impl_api![117; NumPy1; PyArray_CompareUCS4(s1: *mut npy_ucs4, s2: *mut npy_ucs4, len: usize) -> c_int];
173    impl_api![118; PyArray_RemoveSmallest(multi: *mut PyArrayMultiIterObject) -> c_int];
174    impl_api![119; PyArray_ElementStrides(obj: *mut PyObject) -> c_int];
175    impl_api![120; PyArray_Item_INCREF(data: *mut c_char, descr: *mut PyArray_Descr)];
176    impl_api![121; PyArray_Item_XDECREF(data: *mut c_char, descr: *mut PyArray_Descr)];
177    impl_api![122; NumPy1; PyArray_FieldNames(fields: *mut PyObject) -> *mut PyObject];
178    impl_api![123; PyArray_Transpose(ap: *mut PyArrayObject, permute: *mut PyArray_Dims) -> *mut PyObject];
179    impl_api![124; PyArray_TakeFrom(self0: *mut PyArrayObject, indices0: *mut PyObject, axis: c_int, out: *mut PyArrayObject, clipmode: NPY_CLIPMODE) -> *mut PyObject];
180    impl_api![125; PyArray_PutTo(self_: *mut PyArrayObject, values0: *mut PyObject, indices0: *mut PyObject, clipmode: NPY_CLIPMODE) -> *mut PyObject];
181    impl_api![126; PyArray_PutMask(self_: *mut PyArrayObject, values0: *mut PyObject, mask0: *mut PyObject) -> *mut PyObject];
182    impl_api![127; PyArray_Repeat(aop: *mut PyArrayObject, op: *mut PyObject, axis: c_int) -> *mut PyObject];
183    impl_api![128; PyArray_Choose(ip: *mut PyArrayObject, op: *mut PyObject, out: *mut PyArrayObject, clipmode: NPY_CLIPMODE) -> *mut PyObject];
184    impl_api![129; PyArray_Sort(op: *mut PyArrayObject, axis: c_int, which: NPY_SORTKIND) -> c_int];
185    impl_api![130; PyArray_ArgSort(op: *mut PyArrayObject, axis: c_int, which: NPY_SORTKIND) -> *mut PyObject];
186    impl_api![131; PyArray_SearchSorted(op1: *mut PyArrayObject, op2: *mut PyObject, side: NPY_SEARCHSIDE, perm: *mut PyObject) -> *mut PyObject];
187    impl_api![132; PyArray_ArgMax(op: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
188    impl_api![133; PyArray_ArgMin(op: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
189    impl_api![134; PyArray_Reshape(self_: *mut PyArrayObject, shape: *mut PyObject) -> *mut PyObject];
190    impl_api![135; PyArray_Newshape(self_: *mut PyArrayObject, newdims: *mut PyArray_Dims, order: NPY_ORDER) -> *mut PyObject];
191    impl_api![136; PyArray_Squeeze(self_: *mut PyArrayObject) -> *mut PyObject];
192    impl_api![137; PyArray_View(self_: *mut PyArrayObject, type_: *mut PyArray_Descr, pytype: *mut PyTypeObject) -> *mut PyObject];
193    impl_api![138; PyArray_SwapAxes(ap: *mut PyArrayObject, a1: c_int, a2: c_int) -> *mut PyObject];
194    impl_api![139; PyArray_Max(ap: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
195    impl_api![140; PyArray_Min(ap: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
196    impl_api![141; PyArray_Ptp(ap: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
197    impl_api![142; PyArray_Mean(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
198    impl_api![143; PyArray_Trace(self_: *mut PyArrayObject, offset: c_int, axis1: c_int, axis2: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
199    impl_api![144; PyArray_Diagonal(self_: *mut PyArrayObject, offset: c_int, axis1: c_int, axis2: c_int) -> *mut PyObject];
200    impl_api![145; PyArray_Clip(self_: *mut PyArrayObject, min: *mut PyObject, max: *mut PyObject, out: *mut PyArrayObject) -> *mut PyObject];
201    impl_api![146; PyArray_Conjugate(self_: *mut PyArrayObject, out: *mut PyArrayObject) -> *mut PyObject];
202    impl_api![147; PyArray_Nonzero(self_: *mut PyArrayObject) -> *mut PyObject];
203    impl_api![148; PyArray_Std(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject, variance: c_int) -> *mut PyObject];
204    impl_api![149; PyArray_Sum(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
205    impl_api![150; PyArray_CumSum(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
206    impl_api![151; PyArray_Prod(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
207    impl_api![152; PyArray_CumProd(self_: *mut PyArrayObject, axis: c_int, rtype: c_int, out: *mut PyArrayObject) -> *mut PyObject];
208    impl_api![153; PyArray_All(self_: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
209    impl_api![154; PyArray_Any(self_: *mut PyArrayObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
210    impl_api![155; PyArray_Compress(self_: *mut PyArrayObject, condition: *mut PyObject, axis: c_int, out: *mut PyArrayObject) -> *mut PyObject];
211    impl_api![156; PyArray_Flatten(a: *mut PyArrayObject, order: NPY_ORDER) -> *mut PyObject];
212    impl_api![157; PyArray_Ravel(arr: *mut PyArrayObject, order: NPY_ORDER) -> *mut PyObject];
213    impl_api![158; PyArray_MultiplyList(l1: *mut npy_intp, n: c_int) -> npy_intp];
214    impl_api![159; PyArray_MultiplyIntList(l1: *mut c_int, n: c_int) -> c_int];
215    impl_api![160; PyArray_GetPtr(obj: *mut PyArrayObject, ind: *mut npy_intp) -> *mut c_void];
216    impl_api![161; PyArray_CompareLists(l1: *mut npy_intp, l2: *mut npy_intp, n: c_int) -> c_int];
217    impl_api![162; PyArray_AsCArray(op: *mut *mut PyObject, ptr: *mut c_void, dims: *mut npy_intp, nd: c_int, typedescr: *mut PyArray_Descr) -> c_int];
218    impl_api![163; NumPy1; PyArray_As1D(op: *mut *mut PyObject, ptr: *mut *mut c_char, d1: *mut c_int, typecode: c_int) -> c_int];
219    impl_api![164; NumPy1; PyArray_As2D(op: *mut *mut PyObject, ptr: *mut *mut *mut c_char, d1: *mut c_int, d2: *mut c_int, typecode: c_int) -> c_int];
220    impl_api![165; PyArray_Free(op: *mut PyObject, ptr: *mut c_void) -> c_int];
221    impl_api![166; PyArray_Converter(object: *mut PyObject, address: *mut *mut PyObject) -> c_int];
222    impl_api![167; PyArray_IntpFromSequence(seq: *mut PyObject, vals: *mut npy_intp, maxvals: c_int) -> c_int];
223    impl_api![168; PyArray_Concatenate(op: *mut PyObject, axis: c_int) -> *mut PyObject];
224    impl_api![169; PyArray_InnerProduct(op1: *mut PyObject, op2: *mut PyObject) -> *mut PyObject];
225    impl_api![170; PyArray_MatrixProduct(op1: *mut PyObject, op2: *mut PyObject) -> *mut PyObject];
226    impl_api![171; NumPy1; PyArray_CopyAndTranspose(op: *mut PyObject) -> *mut PyObject];
227    impl_api![172; PyArray_Correlate(op1: *mut PyObject, op2: *mut PyObject, mode: c_int) -> *mut PyObject];
228    impl_api![173; NumPy1; PyArray_TypestrConvert(itemsize: c_int, gentype: c_int) -> c_int];
229    impl_api![174; PyArray_DescrConverter(obj: *mut PyObject, at: *mut *mut PyArray_Descr) -> c_int];
230    impl_api![175; PyArray_DescrConverter2(obj: *mut PyObject, at: *mut *mut PyArray_Descr) -> c_int];
231    impl_api![176; PyArray_IntpConverter(obj: *mut PyObject, seq: *mut PyArray_Dims) -> c_int];
232    impl_api![177; PyArray_BufferConverter(obj: *mut PyObject, buf: *mut PyArray_Chunk) -> c_int];
233    impl_api![178; PyArray_AxisConverter(obj: *mut PyObject, axis: *mut c_int) -> c_int];
234    impl_api![179; PyArray_BoolConverter(object: *mut PyObject, val: *mut npy_bool) -> c_int];
235    impl_api![180; PyArray_ByteorderConverter(obj: *mut PyObject, endian: *mut c_char) -> c_int];
236    impl_api![181; PyArray_OrderConverter(object: *mut PyObject, val: *mut NPY_ORDER) -> c_int];
237    impl_api![182; PyArray_EquivTypes(type1: *mut PyArray_Descr, type2: *mut PyArray_Descr) -> c_uchar];
238    impl_api![183; PyArray_Zeros(nd: c_int, dims: *mut npy_intp, type_: *mut PyArray_Descr, is_f_order: c_int) -> *mut PyObject];
239    impl_api![184; PyArray_Empty(nd: c_int, dims: *mut npy_intp, type_: *mut PyArray_Descr, is_f_order: c_int) -> *mut PyObject];
240    impl_api![185; PyArray_Where(condition: *mut PyObject, x: *mut PyObject, y: *mut PyObject) -> *mut PyObject];
241    impl_api![186; PyArray_Arange(start: f64, stop: f64, step: f64, type_num: c_int) -> *mut PyObject];
242    impl_api![187; PyArray_ArangeObj(start: *mut PyObject, stop: *mut PyObject, step: *mut PyObject, dtype: *mut PyArray_Descr) -> *mut PyObject];
243    impl_api![188; PyArray_SortkindConverter(obj: *mut PyObject, sortkind: *mut NPY_SORTKIND) -> c_int];
244    impl_api![189; PyArray_LexSort(sort_keys: *mut PyObject, axis: c_int) -> *mut PyObject];
245    impl_api![190; PyArray_Round(a: *mut PyArrayObject, decimals: c_int, out: *mut PyArrayObject) -> *mut PyObject];
246    impl_api![191; PyArray_EquivTypenums(typenum1: c_int, typenum2: c_int) -> c_uchar];
247    impl_api![192; PyArray_RegisterDataType(descr: *mut PyArray_DescrProto) -> c_int];
248    impl_api![193; PyArray_RegisterCastFunc(descr: *mut PyArray_Descr, totype: c_int, castfunc: PyArray_VectorUnaryFunc) -> c_int];
249    impl_api![194; PyArray_RegisterCanCast(descr: *mut PyArray_Descr, totype: c_int, scalar: NPY_SCALARKIND) -> c_int];
250    impl_api![195; PyArray_InitArrFuncs(f: *mut PyArray_ArrFuncs)];
251    impl_api![196; PyArray_IntTupleFromIntp(len: c_int, vals: *mut npy_intp) -> *mut PyObject];
252    impl_api![197; NumPy1; PyArray_ElementFromName(str: *mut c_char) -> c_int];
253    impl_api![198; PyArray_ClipmodeConverter(object: *mut PyObject, val: *mut NPY_CLIPMODE) -> c_int];
254    impl_api![199; PyArray_OutputConverter(object: *mut PyObject, address: *mut *mut PyArrayObject) -> c_int];
255    impl_api![200; PyArray_BroadcastToShape(obj: *mut PyObject, dims: *mut npy_intp, nd: c_int) -> *mut PyObject];
256    impl_api![201; NumPy1; _PyArray_SigintHandler(signum: c_int)];
257    impl_api![202; NumPy1; _PyArray_GetSigintBuf() -> *mut c_void];
258    impl_api![203; PyArray_DescrAlignConverter(obj: *mut PyObject, at: *mut *mut PyArray_Descr) -> c_int];
259    impl_api![204; PyArray_DescrAlignConverter2(obj: *mut PyObject, at: *mut *mut PyArray_Descr) -> c_int];
260    impl_api![205; PyArray_SearchsideConverter(obj: *mut PyObject, addr: *mut c_void) -> c_int];
261    impl_api![206; PyArray_CheckAxis(arr: *mut PyArrayObject, axis: *mut c_int, flags: c_int) -> *mut PyObject];
262    impl_api![207; PyArray_OverflowMultiplyList(l1: *mut npy_intp, n: c_int) -> npy_intp];
263    impl_api![208; NumPy1; PyArray_CompareString(s1: *mut c_char, s2: *mut c_char, len: usize) -> c_int];
264    // impl_api![209; PyArray_MultiIterFromObjects(mps: *mut *mut PyObject, n: c_int, nadd: c_int, ...) -> *mut PyObject];
265    impl_api![210; PyArray_GetEndianness() -> c_int];
266    impl_api![211; PyArray_GetNDArrayCFeatureVersion() -> c_uint];
267    impl_api![212; PyArray_Correlate2(op1: *mut PyObject, op2: *mut PyObject, mode: c_int) -> *mut PyObject];
268    impl_api![213; PyArray_NeighborhoodIterNew(x: *mut PyArrayIterObject, bounds: *mut npy_intp, mode: c_int, fill: *mut PyArrayObject) -> *mut PyObject];
269    impl_api![219; NumPy1; PyArray_SetDatetimeParseFunction(op: *mut PyObject)];
270    impl_api![220; NumPy1; PyArray_DatetimeToDatetimeStruct(val: npy_datetime, fr: NPY_DATETIMEUNIT, result: *mut npy_datetimestruct)];
271    impl_api![221; NumPy1; PyArray_TimedeltaToTimedeltaStruct(val: npy_timedelta, fr: NPY_DATETIMEUNIT, result: *mut npy_timedeltastruct)];
272    impl_api![222; NumPy1; PyArray_DatetimeStructToDatetime(fr: NPY_DATETIMEUNIT, d: *mut npy_datetimestruct) -> npy_datetime];
273    impl_api![223; NumPy1; PyArray_TimedeltaStructToTimedelta(fr: NPY_DATETIMEUNIT, d: *mut npy_timedeltastruct) -> npy_datetime];
274    impl_api![224; NpyIter_New(op: *mut PyArrayObject, flags: npy_uint32, order: NPY_ORDER, casting: NPY_CASTING, dtype: *mut PyArray_Descr) -> *mut NpyIter];
275    impl_api![225; NpyIter_MultiNew(nop: c_int, op_in: *mut *mut PyArrayObject, flags: npy_uint32, order: NPY_ORDER, casting: NPY_CASTING, op_flags: *mut npy_uint32, op_request_dtypes: *mut *mut PyArray_Descr) -> *mut NpyIter];
276    impl_api![226; NpyIter_AdvancedNew(nop: c_int, op_in: *mut *mut PyArrayObject, flags: npy_uint32, order: NPY_ORDER, casting: NPY_CASTING, op_flags: *mut npy_uint32, op_request_dtypes: *mut *mut PyArray_Descr, oa_ndim: c_int, op_axes: *mut *mut c_int, itershape: *mut npy_intp, buffersize: npy_intp) -> *mut NpyIter];
277    impl_api![227; NpyIter_Copy(iter: *mut NpyIter) -> *mut NpyIter];
278    impl_api![228; NpyIter_Deallocate(iter: *mut NpyIter) -> c_int];
279    impl_api![229; NpyIter_HasDelayedBufAlloc(iter: *mut NpyIter) -> npy_bool];
280    impl_api![230; NpyIter_HasExternalLoop(iter: *mut NpyIter) -> npy_bool];
281    impl_api![231; NpyIter_EnableExternalLoop(iter: *mut NpyIter) -> c_int];
282    impl_api![232; NpyIter_GetInnerStrideArray(iter: *mut NpyIter) -> *mut npy_intp];
283    impl_api![233; NpyIter_GetInnerLoopSizePtr(iter: *mut NpyIter) -> *mut npy_intp];
284    impl_api![234; NpyIter_Reset(iter: *mut NpyIter, errmsg: *mut *mut c_char) -> c_int];
285    impl_api![235; NpyIter_ResetBasePointers(iter: *mut NpyIter, baseptrs: *mut *mut c_char, errmsg: *mut *mut c_char) -> c_int];
286    impl_api![236; NpyIter_ResetToIterIndexRange(iter: *mut NpyIter, istart: npy_intp, iend: npy_intp, errmsg: *mut *mut c_char) -> c_int];
287    impl_api![237; NpyIter_GetNDim(iter: *mut NpyIter) -> c_int];
288    impl_api![238; NpyIter_GetNOp(iter: *mut NpyIter) -> c_int];
289    impl_api![239; NpyIter_GetIterNext(iter: *mut NpyIter, errmsg: *mut *mut c_char) -> NpyIter_IterNextFunc];
290    impl_api![240; NpyIter_GetIterSize(iter: *mut NpyIter) -> npy_intp];
291    impl_api![241; NpyIter_GetIterIndexRange(iter: *mut NpyIter, istart: *mut npy_intp, iend: *mut npy_intp)];
292    impl_api![242; NpyIter_GetIterIndex(iter: *mut NpyIter) -> npy_intp];
293    impl_api![243; NpyIter_GotoIterIndex(iter: *mut NpyIter, iterindex: npy_intp) -> c_int];
294    impl_api![244; NpyIter_HasMultiIndex(iter: *mut NpyIter) -> npy_bool];
295    impl_api![245; NpyIter_GetShape(iter: *mut NpyIter, outshape: *mut npy_intp) -> c_int];
296    impl_api![246; NpyIter_GetGetMultiIndex(iter: *mut NpyIter, errmsg: *mut *mut c_char) -> NpyIter_GetMultiIndexFunc];
297    impl_api![247; NpyIter_GotoMultiIndex(iter: *mut NpyIter, multi_index: *mut npy_intp) -> c_int];
298    impl_api![248; NpyIter_RemoveMultiIndex(iter: *mut NpyIter) -> c_int];
299    impl_api![249; NpyIter_HasIndex(iter: *mut NpyIter) -> npy_bool];
300    impl_api![250; NpyIter_IsBuffered(iter: *mut NpyIter) -> npy_bool];
301    impl_api![251; NpyIter_IsGrowInner(iter: *mut NpyIter) -> npy_bool];
302    impl_api![252; NpyIter_GetBufferSize(iter: *mut NpyIter) -> npy_intp];
303    impl_api![253; NpyIter_GetIndexPtr(iter: *mut NpyIter) -> *mut npy_intp];
304    impl_api![254; NpyIter_GotoIndex(iter: *mut NpyIter, flat_index: npy_intp) -> c_int];
305    impl_api![255; NpyIter_GetDataPtrArray(iter: *mut NpyIter) -> *mut *mut c_char];
306    impl_api![256; NpyIter_GetDescrArray(iter: *mut NpyIter) -> *mut *mut PyArray_Descr];
307    impl_api![257; NpyIter_GetOperandArray(iter: *mut NpyIter) -> *mut *mut PyArrayObject];
308    impl_api![258; NpyIter_GetIterView(iter: *mut NpyIter, i: npy_intp) -> *mut PyArrayObject];
309    impl_api![259; NpyIter_GetReadFlags(iter: *mut NpyIter, outreadflags: *mut c_char)];
310    impl_api![260; NpyIter_GetWriteFlags(iter: *mut NpyIter, outwriteflags: *mut c_char)];
311    impl_api![261; NpyIter_DebugPrint(iter: *mut NpyIter)];
312    impl_api![262; NpyIter_IterationNeedsAPI(iter: *mut NpyIter) -> npy_bool];
313    impl_api![263; NpyIter_GetInnerFixedStrideArray(iter: *mut NpyIter, out_strides: *mut npy_intp)];
314    impl_api![264; NpyIter_RemoveAxis(iter: *mut NpyIter, axis: c_int) -> c_int];
315    impl_api![265; NpyIter_GetAxisStrideArray(iter: *mut NpyIter, axis: c_int) -> *mut npy_intp];
316    impl_api![266; NpyIter_RequiresBuffering(iter: *mut NpyIter) -> npy_bool];
317    impl_api![267; NpyIter_GetInitialDataPtrArray(iter: *mut NpyIter) -> *mut *mut c_char];
318    impl_api![268; NpyIter_CreateCompatibleStrides(iter: *mut NpyIter, itemsize: npy_intp, outstrides: *mut npy_intp) -> c_int];
319    impl_api![269; PyArray_CastingConverter(obj: *mut PyObject, casting: *mut NPY_CASTING) -> c_int];
320    impl_api![270; PyArray_CountNonzero(self_: *mut PyArrayObject) -> npy_intp];
321    impl_api![271; PyArray_PromoteTypes(type1: *mut PyArray_Descr, type2: *mut PyArray_Descr) -> *mut PyArray_Descr];
322    impl_api![272; PyArray_MinScalarType(arr: *mut PyArrayObject) -> *mut PyArray_Descr];
323    impl_api![273; PyArray_ResultType(narrs: npy_intp, arr: *mut *mut PyArrayObject, ndtypes: npy_intp, dtypes: *mut *mut PyArray_Descr) -> *mut PyArray_Descr];
324    impl_api![274; PyArray_CanCastArrayTo(arr: *mut PyArrayObject, to: *mut PyArray_Descr, casting: NPY_CASTING) -> npy_bool];
325    impl_api![275; PyArray_CanCastTypeTo(from: *mut PyArray_Descr, to: *mut PyArray_Descr, casting: NPY_CASTING) -> npy_bool];
326    impl_api![276; PyArray_EinsteinSum(subscripts: *mut c_char, nop: npy_intp, op_in: *mut *mut PyArrayObject, dtype: *mut PyArray_Descr, order: NPY_ORDER, casting: NPY_CASTING, out: *mut PyArrayObject) -> *mut PyObject];
327    impl_api![277; PyArray_NewLikeArray(prototype: *mut PyArrayObject, order: NPY_ORDER, dtype: *mut PyArray_Descr, subok: c_int) -> *mut PyObject];
328    impl_api![278; NumPy1; PyArray_GetArrayParamsFromObject(op: *mut PyObject, requested_dtype: *mut PyArray_Descr, writeable: npy_bool, out_dtype: *mut *mut PyArray_Descr, out_ndim: *mut c_int, out_dims: *mut npy_intp, out_arr: *mut *mut PyArrayObject, context: *mut PyObject) -> c_int];
329    impl_api![279; PyArray_ConvertClipmodeSequence(object: *mut PyObject, modes: *mut NPY_CLIPMODE, n: c_int) -> c_int];
330    impl_api![280; PyArray_MatrixProduct2(op1: *mut PyObject, op2: *mut PyObject, out: *mut PyArrayObject) -> *mut PyObject];
331    impl_api![281; NpyIter_IsFirstVisit(iter: *mut NpyIter, iop: c_int) -> npy_bool];
332    impl_api![282; PyArray_SetBaseObject(arr: *mut PyArrayObject, obj: *mut PyObject) -> c_int];
333    impl_api![283; PyArray_CreateSortedStridePerm(ndim: c_int, strides: *mut npy_intp, out_strideperm: *mut npy_stride_sort_item)];
334    impl_api![284; PyArray_RemoveAxesInPlace(arr: *mut PyArrayObject, flags: *mut npy_bool)];
335    impl_api![285; PyArray_DebugPrint(obj: *mut PyArrayObject)];
336    impl_api![286; PyArray_FailUnlessWriteable(obj: *mut PyArrayObject, name: *const c_char) -> c_int];
337    impl_api![287; PyArray_SetUpdateIfCopyBase(arr: *mut PyArrayObject, base: *mut PyArrayObject) -> c_int];
338    impl_api![288; PyDataMem_NEW(size: usize) -> *mut c_void];
339    impl_api![289; PyDataMem_FREE(ptr: *mut c_void)];
340    impl_api![290; PyDataMem_RENEW(ptr: *mut c_void, size: usize) -> *mut c_void];
341    impl_api![291; NumPy1; PyDataMem_SetEventHook(newhook: PyDataMem_EventHookFunc, user_data: *mut c_void, old_data: *mut *mut c_void) -> PyDataMem_EventHookFunc];
342    impl_api![293; NumPy1; PyArray_MapIterSwapAxes(mit: *mut PyArrayMapIterObject, ret: *mut *mut PyArrayObject, getmap: c_int)];
343    impl_api![294; NumPy1; PyArray_MapIterArray(a: *mut PyArrayObject, index: *mut PyObject) -> *mut PyObject];
344    impl_api![295; NumPy1; PyArray_MapIterNext(mit: *mut PyArrayMapIterObject)];
345    impl_api![296; PyArray_Partition(op: *mut PyArrayObject, ktharray: *mut PyArrayObject, axis: c_int, which: NPY_SELECTKIND) -> c_int];
346    impl_api![297; PyArray_ArgPartition(op: *mut PyArrayObject, ktharray: *mut PyArrayObject, axis: c_int, which: NPY_SELECTKIND) -> *mut PyObject];
347    impl_api![298; PyArray_SelectkindConverter(obj: *mut PyObject, selectkind: *mut NPY_SELECTKIND) -> c_int];
348    impl_api![299; PyDataMem_NEW_ZEROED(size: usize, elsize: usize) -> *mut c_void];
349    impl_api![300; PyArray_CheckAnyScalarExact(obj: *mut PyObject) -> c_int];
350    impl_api![301; NumPy1; PyArray_MapIterArrayCopyIfOverlap(a: *mut PyArrayObject, index: *mut PyObject, copy_if_overlap: c_int, extra_op: *mut PyArrayObject) -> *mut PyObject];
351    impl_api![302; PyArray_ResolveWritebackIfCopy(self_: *mut PyArrayObject) -> c_int];
352    impl_api![303; PyArray_SetWritebackIfCopyBase(arr: *mut PyArrayObject, base: *mut PyArrayObject) -> c_int];
353    impl_api![304; PyDataMem_SetHandler(handler: *mut PyObject) -> *mut PyObject];
354    impl_api![305; PyDataMem_GetHandler() -> *mut PyObject];
355    impl_api![307; NumPy2; NpyDatetime_ConvertDatetime64ToDatetimeStruct(meta: *mut PyArray_DatetimeMetaData, dt: npy_datetime, out: *mut npy_datetimestruct) -> c_int];
356    impl_api![308; NumPy2; NpyDatetime_ConvertDatetimeStructToDatetime64(meta: *mut PyArray_DatetimeMetaData, dts: *const npy_datetimestruct, out: *mut npy_datetime) -> c_int];
357    impl_api![309; NumPy2; NpyDatetime_ConvertPyDateTimeToDatetimeStruct(obj: *mut PyObject, out: *mut npy_datetimestruct, out_bestunit: *mut NPY_DATETIMEUNIT,  apply_tzinfo: c_int) -> c_int];
358    impl_api![310; NumPy2; NpyDatetime_GetDatetimeISO8601StrLen(local: c_int, base: NPY_DATETIMEUNIT) -> c_int];
359    impl_api![311; NumPy2; NpyDatetime_MakeISO8601Datetime(dts: *mut npy_datetimestruct, outstr: *mut c_char, outlen: npy_intp, local: c_int, utc: c_int, base: NPY_DATETIMEUNIT, tzoffset: c_int, casting: NPY_CASTING) -> c_int];
360    impl_api![312; NumPy2; NpyDatetime_ParseISO8601Datetime(str: *const c_char, len: pyo3::ffi::Py_ssize_t, unit: NPY_DATETIMEUNIT, casting: NPY_CASTING, out: *mut npy_datetimestruct, out_bestunit: *mut NPY_DATETIMEUNIT, out_special: *mut npy_bool) -> c_int];
361    impl_api![313; NumPy2; NpyString_load(allocator: *mut npy_string_allocator, packed_string: *const npy_packed_static_string, unpacked_string: *mut npy_static_string) -> c_int];
362    impl_api![314; NumPy2; NpyString_pack(out: *mut npy_packed_static_string) -> c_int];
363    impl_api![315; NumPy2; NpyString_pack_null(allocator: *mut npy_string_allocator, packed_string: *mut npy_packed_static_string) -> c_int];
364    impl_api![316; NumPy2; NpyString_acquire_allocator(descr: *const PyArray_StringDTypeObject) -> *mut npy_string_allocator];
365    impl_api![317; NumPy2; NpyString_acquire_allocators(n_descriptors: usize, descrs: *const *mut PyArray_Descr, allocators: *mut *mut npy_string_allocator)];
366    impl_api![318; NumPy2; NpyString_release_allocator(allocator: *mut npy_string_allocator)];
367    impl_api![319; NumPy2; NpyString_release_allocators(length: usize, allocators: *mut *mut npy_string_allocator)];
368    impl_api![361; NumPy2; PyArray_GetDefaultDescr(DType: *mut PyArray_DTypeMeta) -> *mut PyArray_Descr];
369    impl_api![362; NumPy2; PyArrayInitDTypeMeta_FromSpec(DType: *mut PyArray_DTypeMeta, spec: *mut PyArrayDTypeMeta_Spec) -> c_int];
370    impl_api![363; NumPy2; PyArray_CommonDType(dtype1: *mut PyArray_DTypeMeta, dtype2: *mut PyArray_DTypeMeta) -> PyArray_DTypeMeta];
371    impl_api![364; NumPy2; PyArray_PromoteDTypeSequence(length: npy_intp, dtypes_in: *mut *mut PyArray_DTypeMeta) -> *mut PyArray_DTypeMeta];
372    impl_api![365; NumPy2; _PyDataType_GetArrFuncs(descr: *const PyArray_Descr) -> *mut PyArray_ArrFuncs];
373
374    #[allow(non_snake_case)]
375    pub unsafe fn PyArray_CopyInto<'py>(
376        &self,
377        py: Python<'py>,
378        dst: *mut PyArrayObject,
379        src: *mut PyArrayObject,
380    ) -> c_int {
381        let offset = if is_numpy_2(py) { 50 } else { 82 };
382        let fptr = self.get(py, offset)
383            as *const extern "C" fn(dst: *mut PyArrayObject, src: *mut PyArrayObject) -> c_int;
384        (*fptr)(dst, src)
385    }
386
387    #[allow(non_snake_case)]
388    pub unsafe fn PyArray_CastAnyTo<'py>(
389        &self,
390        py: Python<'py>,
391        out: *mut PyArrayObject,
392        mp: *mut PyArrayObject,
393    ) -> c_int {
394        let offset = if is_numpy_2(py) { 51 } else { 83 };
395        let fptr = self.get(py, offset)
396            as *const extern "C" fn(out: *mut PyArrayObject, mp: *mut PyArrayObject) -> c_int;
397        (*fptr)(out, mp)
398    }
399}
400
401// Define type objects associated with the NumPy API
402macro_rules! impl_array_type {
403    ($(($offset:expr, $tname:ident)),*) => {
404        /// All type objects exported by the NumPy API.
405        #[allow(non_camel_case_types)]
406        pub enum NpyTypes { $($tname),* }
407
408        impl PyArrayAPI {
409            /// Get a pointer of the type object assocaited with `ty`.
410            pub unsafe fn get_type_object<'py>(&self, py: Python<'py>, ty: NpyTypes) -> *mut PyTypeObject {
411                match ty {
412                    $( NpyTypes::$tname => *(self.get(py, $offset)) as _ ),*
413                }
414            }
415        }
416    }
417}
418
419impl_array_type! {
420    (1, PyBigArray_Type),
421    (2, PyArray_Type),
422    (3, PyArrayDescr_Type),
423    (4, PyArrayFlags_Type),
424    (5, PyArrayIter_Type),
425    (6, PyArrayMultiIter_Type),
426    (7, NPY_NUMUSERTYPES),
427    (8, PyBoolArrType_Type),
428    (9, _PyArrayScalar_BoolValues),
429    (10, PyGenericArrType_Type),
430    (11, PyNumberArrType_Type),
431    (12, PyIntegerArrType_Type),
432    (13, PySignedIntegerArrType_Type),
433    (14, PyUnsignedIntegerArrType_Type),
434    (15, PyInexactArrType_Type),
435    (16, PyFloatingArrType_Type),
436    (17, PyComplexFloatingArrType_Type),
437    (18, PyFlexibleArrType_Type),
438    (19, PyCharacterArrType_Type),
439    (20, PyByteArrType_Type),
440    (21, PyShortArrType_Type),
441    (22, PyIntArrType_Type),
442    (23, PyLongArrType_Type),
443    (24, PyLongLongArrType_Type),
444    (25, PyUByteArrType_Type),
445    (26, PyUShortArrType_Type),
446    (27, PyUIntArrType_Type),
447    (28, PyULongArrType_Type),
448    (29, PyULongLongArrType_Type),
449    (30, PyFloatArrType_Type),
450    (31, PyDoubleArrType_Type),
451    (32, PyLongDoubleArrType_Type),
452    (33, PyCFloatArrType_Type),
453    (34, PyCDoubleArrType_Type),
454    (35, PyCLongDoubleArrType_Type),
455    (36, PyObjectArrType_Type),
456    (37, PyStringArrType_Type),
457    (38, PyUnicodeArrType_Type),
458    (39, PyVoidArrType_Type)
459}
460
461/// Checks that `op` is an instance of `PyArray` or not.
462#[allow(non_snake_case)]
463pub unsafe fn PyArray_Check<'py>(py: Python<'py>, op: *mut PyObject) -> c_int {
464    ffi::PyObject_TypeCheck(op, PY_ARRAY_API.get_type_object(py, NpyTypes::PyArray_Type))
465}
466
467/// Checks that `op` is an exact instance of `PyArray` or not.
468#[allow(non_snake_case)]
469pub unsafe fn PyArray_CheckExact<'py>(py: Python<'py>, op: *mut PyObject) -> c_int {
470    (ffi::Py_TYPE(op) == PY_ARRAY_API.get_type_object(py, NpyTypes::PyArray_Type)) as _
471}
472
473#[cfg(test)]
474mod tests {
475    use super::*;
476
477    #[test]
478    fn call_api() {
479        Python::with_gil(|py| unsafe {
480            assert_eq!(
481                PY_ARRAY_API.PyArray_MultiplyIntList(py, [1, 2, 3].as_mut_ptr(), 3),
482                6
483            );
484        })
485    }
486}