Skip to content

Commit 9f225e5

Browse files
committed
Cleanup PyArray/PyUFunc API and use numpy.org URL
1 parent e0c3b64 commit 9f225e5

File tree

6 files changed

+66
-71
lines changed

6 files changed

+66
-71
lines changed

src/array.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::slice_box::SliceBox;
1616
use crate::types::{NpyDataType, TypeNum};
1717

1818
/// A safe, static-typed interface for
19-
/// [NumPy ndarray](https://docs.scipy.org/doc/numpy/reference/arrays.ndarray.html).
19+
/// [NumPy ndarray](https://numpy.org/doc/stable/reference/arrays.ndarray.html).
2020
///
2121
/// # Memory location
2222
///
@@ -226,7 +226,7 @@ impl<T, D> PyArray<T, D> {
226226

227227
/// Returns the number of dimensions in the array.
228228
///
229-
/// Same as [numpy.ndarray.ndim](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.ndim.html)
229+
/// Same as [numpy.ndarray.ndim](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.ndim.html)
230230
///
231231
/// # Example
232232
/// ```
@@ -237,15 +237,15 @@ impl<T, D> PyArray<T, D> {
237237
/// assert_eq!(arr.ndim(), 3);
238238
/// # }
239239
/// ```
240-
// C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_NDIM
240+
// C API: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_NDIM
241241
pub fn ndim(&self) -> usize {
242242
let ptr = self.as_array_ptr();
243243
unsafe { (*ptr).nd as usize }
244244
}
245245

246246
/// Returns a slice which contains how many bytes you need to jump to the next row.
247247
///
248-
/// Same as [numpy.ndarray.strides](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.strides.html)
248+
/// Same as [numpy.ndarray.strides](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.strides.html)
249249
/// # Example
250250
/// ```
251251
/// # fn main() {
@@ -255,7 +255,7 @@ impl<T, D> PyArray<T, D> {
255255
/// assert_eq!(arr.strides(), &[240, 48, 8]);
256256
/// # }
257257
/// ```
258-
// C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_STRIDES
258+
// C API: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_STRIDES
259259
pub fn strides(&self) -> &[isize] {
260260
let n = self.ndim();
261261
let ptr = self.as_array_ptr();
@@ -267,7 +267,7 @@ impl<T, D> PyArray<T, D> {
267267

268268
/// Returns a slice which contains dimmensions of the array.
269269
///
270-
/// Same as [numpy.ndarray.shape](https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.shape.html)
270+
/// Same as [numpy.ndarray.shape](https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html)
271271
/// # Example
272272
/// ```
273273
/// # fn main() {
@@ -277,7 +277,7 @@ impl<T, D> PyArray<T, D> {
277277
/// assert_eq!(arr.shape(), &[4, 5, 6]);
278278
/// # }
279279
/// ```
280-
// C API: https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_DIMS
280+
// C API: https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_DIMS
281281
pub fn shape(&self) -> &[usize] {
282282
let n = self.ndim();
283283
let ptr = self.as_array_ptr();
@@ -415,7 +415,7 @@ impl<T: TypeNum, D: Dimension> PyArray<T, D> {
415415
/// If `is_fortran` is true, then
416416
/// a fortran order array is created, otherwise a C-order array is created.
417417
///
418-
/// See also [PyArray_Zeros](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Zeros)
418+
/// See also [PyArray_Zeros](https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Zeros)
419419
///
420420
/// # Example
421421
/// ```
@@ -1037,9 +1037,9 @@ impl<T: TypeNum, D> PyArray<T, D> {
10371037

10381038
impl<T: TypeNum + AsPrimitive<f64>> PyArray<T, Ix1> {
10391039
/// Return evenly spaced values within a given interval.
1040-
/// Same as [numpy.arange](https://docs.scipy.org/doc/numpy/reference/generated/numpy.arange.html).
1040+
/// Same as [numpy.arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html).
10411041
///
1042-
/// See also [PyArray_Arange](https://docs.scipy.org/doc/numpy/reference/c-api.array.html#c.PyArray_Arange).
1042+
/// See also [PyArray_Arange](https://numpy.org/doc/stable/reference/c-api/array.html#c.PyArray_Arange).
10431043
///
10441044
/// # Example
10451045
/// ```

src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//! `rust-numpy` provides Rust interfaces for [NumPy C APIs](https://docs.scipy.org/doc/numpy/reference/c-api.html),
2-
//! especially for [ndarray](https://www.numpy.org/devdocs/reference/arrays.ndarray.html) class.
1+
//! `rust-numpy` provides Rust interfaces for [NumPy C APIs](https://numpy.org/doc/stable/reference/c-api),
2+
//! especially for [ndarray](https://numpy.org/doc/stable/reference/arrays.ndarray.html) class.
33
//!
44
//! It uses [pyo3](https://github.com/PyO3/pyo3) for rust bindings to cpython, and uses
55
//! [ndarray](https://github.com/bluss/ndarray) for rust side matrix library.

src/npyffi/array.rs

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
//! Low-Level binding for [Array API](https://docs.scipy.org/doc/numpy/reference/c-api.array.html)
1+
//! Low-Level binding for [Array API](https://numpy.org/doc/stable/reference/c-api/array.html)
22
use libc::FILE;
33
use pyo3::ffi::{self, PyObject, PyTypeObject};
4-
use std::ops::Deref;
54
use std::os::raw::*;
6-
use std::ptr;
75
use std::sync::Once;
6+
use std::{cell::Cell, ptr};
87

98
use crate::npyffi::*;
109

1110
pub(crate) const MOD_NAME: &str = "numpy.core.multiarray";
1211
const CAPSULE_NAME: &str = "_ARRAY_API";
1312

1413
/// A global variable which stores a ['capsule'](https://docs.python.org/3/c-api/capsule.html)
15-
/// pointer to [Numpy Array API](https://docs.scipy.org/doc/numpy/reference/c-api.array.html).
14+
/// pointer to [Numpy Array API](https://numpy.org/doc/stable/reference/c-api/array.html).
1615
///
1716
/// You can acceess raw c APIs via this variable and its Deref implementation.
1817
///
@@ -31,35 +30,33 @@ const CAPSULE_NAME: &str = "_ARRAY_API";
3130
/// assert_eq!(array.as_slice().unwrap(), &[2, 3, 4])
3231
/// # }
3332
/// ```
34-
pub static PY_ARRAY_API: PyArrayAPI = PyArrayAPI {
35-
__private_field: (),
36-
};
33+
pub static PY_ARRAY_API: PyArrayAPI = PyArrayAPI::new();
3734

35+
/// See [PY_ARRAY_API] for more.
3836
pub struct PyArrayAPI {
39-
__private_field: (),
37+
once: Once,
38+
api: Cell<*const *const c_void>,
4039
}
4140

42-
impl Deref for PyArrayAPI {
43-
type Target = PyArrayAPI_Inner;
44-
fn deref(&self) -> &Self::Target {
45-
static INIT_API: Once = Once::new();
46-
static mut ARRAY_API_CACHE: PyArrayAPI_Inner = PyArrayAPI_Inner(ptr::null());
47-
unsafe {
48-
if ARRAY_API_CACHE.0.is_null() {
49-
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
50-
INIT_API.call_once(move || {
51-
ARRAY_API_CACHE = PyArrayAPI_Inner(api);
52-
});
53-
}
54-
&ARRAY_API_CACHE
41+
impl PyArrayAPI {
42+
const fn new() -> Self {
43+
Self {
44+
once: Once::new(),
45+
api: Cell::new(ptr::null_mut()),
46+
}
47+
}
48+
fn get(&self, offset: isize) -> *const *const c_void {
49+
if self.api.get().is_null() {
50+
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
51+
self.once.call_once(|| self.api.set(api));
5552
}
53+
unsafe { self.api.get().offset(offset) }
5654
}
5755
}
5856

59-
#[allow(non_camel_case_types)]
60-
pub struct PyArrayAPI_Inner(*const *const c_void);
57+
unsafe impl Sync for PyArrayAPI {}
6158

62-
impl PyArrayAPI_Inner {
59+
impl PyArrayAPI {
6360
impl_api![0; PyArray_GetNDArrayCVersion() -> c_uint];
6461
impl_api![40; PyArray_SetNumericOps(dict: *mut PyObject) -> c_int];
6562
impl_api![41; PyArray_GetNumericOps() -> *mut PyObject];
@@ -322,13 +319,15 @@ impl PyArrayAPI_Inner {
322319
/// Define PyTypeObject related to Array API
323320
macro_rules! impl_array_type {
324321
($(($offset:expr, $tname:ident)),*) => {
322+
/// All type objects that numpy has.
325323
#[allow(non_camel_case_types)]
326324
#[repr(i32)]
327325
pub enum ArrayType { $($tname),* }
328-
impl PyArrayAPI_Inner {
326+
impl PyArrayAPI {
327+
/// Get the pointer of the type object that `self` refers.
329328
pub unsafe fn get_type_object(&self, ty: ArrayType) -> *mut PyTypeObject {
330329
match ty {
331-
$( ArrayType::$tname => *(self.0.offset($offset)) as *mut PyTypeObject ),*
330+
$( ArrayType::$tname => *(self.get($offset)) as *mut PyTypeObject ),*
332331
}
333332
}
334333
}
@@ -377,11 +376,13 @@ impl_array_type!(
377376
(39, PyVoidArrType_Type)
378377
);
379378

379+
/// Checks that `op` is an instance of `PyArray` or not.
380380
#[allow(non_snake_case)]
381381
pub unsafe fn PyArray_Check(op: *mut PyObject) -> c_int {
382382
ffi::PyObject_TypeCheck(op, PY_ARRAY_API.get_type_object(ArrayType::PyArray_Type))
383383
}
384384

385+
/// Checks that `op` is an exact instance of `PyArray` or not.
385386
#[allow(non_snake_case)]
386387
pub unsafe fn PyArray_CheckExact(op: *mut PyObject) -> c_int {
387388
(ffi::Py_TYPE(op) == PY_ARRAY_API.get_type_object(ArrayType::PyArray_Type)) as c_int

src/npyffi/mod.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Low-Level bindings for NumPy C API.
22
//!
3-
//! https://docs.scipy.org/doc/numpy/reference/c-api.html
3+
//! https://numpy.org/doc/stable/reference/c-api
44
#![allow(non_camel_case_types)]
55

66
use pyo3::ffi;
@@ -11,9 +11,6 @@ use std::ptr::null_mut;
1111
fn get_numpy_api(module: &str, capsule: &str) -> *const *const c_void {
1212
let module = CString::new(module).unwrap();
1313
let capsule = CString::new(capsule).unwrap();
14-
unsafe fn get_capsule(capsule: *mut ffi::PyObject) -> *const *const c_void {
15-
ffi::PyCapsule_GetPointer(capsule, null_mut()) as *const *const c_void
16-
}
1714
unsafe {
1815
assert_ne!(
1916
ffi::Py_IsInitialized(),
@@ -23,9 +20,9 @@ Please make sure that you get gil, by `let gil = Python::acquire_gil();`"
2320
);
2421
let numpy = ffi::PyImport_ImportModule(module.as_ptr());
2522
assert!(!numpy.is_null(), "Failed to import numpy module");
26-
let capsule = ffi::PyObject_GetAttrString(numpy as *mut ffi::PyObject, capsule.as_ptr());
23+
let capsule = ffi::PyObject_GetAttrString(numpy as _, capsule.as_ptr());
2724
assert!(!capsule.is_null(), "Failed to import numpy module");
28-
get_capsule(capsule)
25+
ffi::PyCapsule_GetPointer(capsule, null_mut()) as _
2926
}
3027
}
3128

@@ -34,8 +31,8 @@ macro_rules! impl_api {
3431
[ $offset:expr; $fname:ident ( $($arg:ident : $t:ty),* ) $( -> $ret:ty )* ] => {
3532
#[allow(non_snake_case)]
3633
pub unsafe fn $fname(&self, $($arg : $t), *) $( -> $ret )* {
37-
let fptr = self.0.offset($offset)
38-
as *const extern fn ($($arg : $t), *) $( -> $ret )*;
34+
let fptr = self.get($offset)
35+
as *const extern fn ($($arg : $t), *) $( -> $ret )*;
3936
(*fptr)($($arg), *)
4037
}
4138
}

src/npyffi/objects.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Low-Lebel binding for NumPy C API C-objects
22
//!
3-
//! https://docs.scipy.org/doc/numpy/reference/c-api.types-and-structures.html
3+
//! https://numpy.org/doc/stable/reference/c-api/types-and-structures.html
44
#![allow(non_camel_case_types)]
55

66
use libc::FILE;

src/npyffi/ufunc.rs

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
1-
//! Low-Level binding for [UFunc API](https://docs.scipy.org/doc/numpy/reference/c-api.ufunc.html)
1+
//! Low-Level binding for [UFunc API](https://numpy.org/doc/stable/reference/c-api/ufunc.html)
22
3-
use std::ops::Deref;
43
use std::os::raw::*;
5-
use std::ptr;
6-
use std::sync::Once;
4+
use std::{cell::Cell, ptr, sync::Once};
75

86
use pyo3::ffi::PyObject;
97

@@ -14,35 +12,34 @@ use super::types::*;
1412
const MOD_NAME: &str = "numpy.core.umath";
1513
const CAPSULE_NAME: &str = "_UFUNC_API";
1614

17-
pub static PY_UFUNC_API: PyUFuncAPI = PyUFuncAPI {
18-
__private_field: (),
19-
};
15+
/// A global variable which stores a ['capsule'](https://docs.python.org/3/c-api/capsule.html)
16+
/// pointer to [Numpy UFunc API](https://numpy.org/doc/stable/reference/c-api/array.html).
17+
pub static PY_UFUNC_API: PyUFuncAPI = PyUFuncAPI::new();
2018

2119
pub struct PyUFuncAPI {
22-
__private_field: (),
20+
once: Once,
21+
api: Cell<*const *const c_void>,
2322
}
2423

25-
impl Deref for PyUFuncAPI {
26-
type Target = PyUFuncAPI_Inner;
27-
fn deref(&self) -> &Self::Target {
28-
static INIT_API: Once = Once::new();
29-
static mut UFUNC_API_CACHE: PyUFuncAPI_Inner = PyUFuncAPI_Inner(ptr::null());
30-
unsafe {
31-
if UFUNC_API_CACHE.0.is_null() {
32-
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
33-
INIT_API.call_once(move || {
34-
UFUNC_API_CACHE = PyUFuncAPI_Inner(api);
35-
});
36-
}
37-
&UFUNC_API_CACHE
24+
impl PyUFuncAPI {
25+
const fn new() -> Self {
26+
Self {
27+
once: Once::new(),
28+
api: Cell::new(ptr::null_mut()),
3829
}
3930
}
31+
fn get(&self, offset: isize) -> *const *const c_void {
32+
if self.api.get().is_null() {
33+
let api = get_numpy_api(MOD_NAME, CAPSULE_NAME);
34+
self.once.call_once(|| self.api.set(api));
35+
}
36+
unsafe { self.api.get().offset(offset) }
37+
}
4038
}
4139

42-
#[allow(non_camel_case_types)]
43-
pub struct PyUFuncAPI_Inner(*const *const c_void);
40+
unsafe impl Sync for PyUFuncAPI {}
4441

45-
impl PyUFuncAPI_Inner {
42+
impl PyUFuncAPI {
4643
impl_api![1; PyUFunc_FromFuncAndData(func: *mut PyUFuncGenericFunction, data: *mut *mut c_void, types: *mut c_char, ntypes: c_int, nin: c_int, nout: c_int, identity: c_int, name: *const c_char, doc: *const c_char, unused: c_int) -> *mut PyObject];
4744
impl_api![2; PyUFunc_RegisterLoopForType(ufunc: *mut PyUFuncObject, usertype: c_int, function: PyUFuncGenericFunction, arg_types: *mut c_int, data: *mut c_void) -> c_int];
4845
impl_api![3; PyUFunc_GenericFunction(ufunc: *mut PyUFuncObject, args: *mut PyObject, kwds: *mut PyObject, op: *mut *mut PyArrayObject) -> c_int];

0 commit comments

Comments
 (0)