diff --git a/Cargo.toml b/Cargo.toml index 9fa72de85..d985396e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,8 +14,8 @@ cfg-if = "0.1" libc = "0.2" num-complex = "0.2" num-traits = "0.2" -ndarray = ">=0.12" -pyo3 = "0.8" +ndarray = ">=0.13" +pyo3 = "0.9.0" [features] # In default setting, python version is automatically detected diff --git a/README.md b/README.md index f41aec7a7..f6e8c70fb 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ using [setuptools-rust](https://github.com/PyO3/setuptools-rust). name = "numpy-test" [dependencies] -pyo3 = "0.8" +pyo3 = "0.9.0" numpy = "0.7.0" ``` @@ -102,7 +102,7 @@ numpy = "0.7.0" ndarray = "0.13" [dependencies.pyo3] -version = "0.8" +version = "0.9.0-alpha.1" features = ["extension-module"] ``` diff --git a/examples/linalg/Cargo.toml b/examples/linalg/Cargo.toml index 16acf12fa..0a6ed16cf 100644 --- a/examples/linalg/Cargo.toml +++ b/examples/linalg/Cargo.toml @@ -10,9 +10,9 @@ crate-type = ["cdylib"] [dependencies] numpy = { path = "../.." } -ndarray = ">= 0.12" -ndarray-linalg = { version = "0.10", features = ["openblas"] } +ndarray = ">= 0.13" +ndarray-linalg = { version = "0.12", features = ["openblas"] } [dependencies.pyo3] -version = "0.8" +version = "0.9.0" features = ["extension-module"] diff --git a/examples/simple-extension/Cargo.toml b/examples/simple-extension/Cargo.toml index 97219fbfd..b251ae57a 100644 --- a/examples/simple-extension/Cargo.toml +++ b/examples/simple-extension/Cargo.toml @@ -13,5 +13,5 @@ numpy = { path = "../.." } ndarray = ">= 0.12" [dependencies.pyo3] -version = "0.8" +version = "0.9.0" features = ["extension-module"] diff --git a/src/array.rs b/src/array.rs index 05db9b54a..be65aa598 100644 --- a/src/array.rs +++ b/src/array.rs @@ -2,7 +2,7 @@ use crate::npyffi::{self, npy_intp, NPY_ORDER, PY_ARRAY_API}; use ndarray::*; use num_traits::AsPrimitive; -use pyo3::{ffi, prelude::*, types::PyAny}; +use pyo3::{ffi, prelude::*, type_object, types::PyAny}; use pyo3::{AsPyPointer, PyDowncastError, PyNativeType}; use std::iter::ExactSizeIterator; use std::marker::PhantomData; @@ -99,8 +99,12 @@ pub fn get_array_module(py: Python<'_>) -> PyResult<&PyModule> { PyModule::import(py, npyffi::array::MOD_NAME) } +unsafe impl type_object::PyLayout> for npyffi::PyArrayObject {} +impl type_object::PySizedLayout> for npyffi::PyArrayObject {} + pyobject_native_type_convert!( PyArray, + npyffi::PyArrayObject, *npyffi::PY_ARRAY_API.get_type_object(npyffi::ArrayType::PyArray_Type), Some("numpy"), npyffi::PyArray_Check, @@ -166,7 +170,7 @@ impl PyArray { /// let not_contiguous: &numpy::PyArray1 = py /// .eval("np.zeros((3, 5))[::2, 4]", Some(locals), None) /// .unwrap() - /// .downcast_ref() + /// .downcast() /// .unwrap(); /// assert!(!not_contiguous.is_contiguous()); /// # } @@ -386,19 +390,23 @@ impl PyArray { ID: IntoDimension, { let dims = dims.into_dimension(); - let slice = SliceBox::new(slice); + let container = SliceBox::new(slice); + let data_ptr = container.data; + let cell = pyo3::PyClassInitializer::from(container) + .create_cell(py) + .expect("Object creation failed."); let ptr = PY_ARRAY_API.PyArray_New( PY_ARRAY_API.get_type_object(npyffi::ArrayType::PyArray_Type), dims.ndim_cint(), dims.as_dims_ptr(), T::typenum_default(), strides as *mut _, // strides - slice.data(), // data + data_ptr as _, // data mem::size_of::() as i32, // itemsize 0, // flag ::std::ptr::null_mut(), //obj ); - PY_ARRAY_API.PyArray_SetBaseObject(ptr as *mut npyffi::PyArrayObject, slice.as_ptr()); + PY_ARRAY_API.PyArray_SetBaseObject(ptr as *mut npyffi::PyArrayObject, cell as _); Self::from_owned_ptr(py, ptr) } @@ -451,7 +459,7 @@ impl PyArray { /// let not_contiguous: &PyArray1 = py /// .eval("np.zeros((3, 5))[[0, 2], [3, 4]]", Some(locals), None) /// .unwrap() - /// .downcast_ref() + /// .downcast() /// .unwrap(); /// assert!(not_contiguous.as_slice().is_err()); /// # } diff --git a/src/slice_box.rs b/src/slice_box.rs index 6b5c3fb95..52fee5b0f 100644 --- a/src/slice_box.rs +++ b/src/slice_box.rs @@ -1,43 +1,51 @@ use pyo3::class::methods::{PyMethodDefType, PyMethodsProtocol}; -use pyo3::{ffi, type_object, types::PyAny, AsPyPointer, PyObjectAlloc, Python}; -use std::os::raw::c_void; +use pyo3::pyclass::{PyClass, PyClassAlloc}; +use pyo3::pyclass_slots::PyClassDummySlot; +use pyo3::{ffi, type_object, types::PyAny, PyCell, PyClassInitializer}; -/// It's a memory store for IntoPyArray. -/// See IntoPyArray's doc for what concretely this type is for. -#[repr(C)] pub(crate) struct SliceBox { - ob_base: ffi::PyObject, - inner: *mut [T], + pub(crate) data: *mut [T], } impl SliceBox { - pub(crate) unsafe fn new<'a>(box_: Box<[T]>) -> &'a Self { - let type_ob = ::init_type().as_ptr(); - let base = ffi::_PyObject_New(type_ob); - *base = ffi::PyObject_HEAD_INIT; - (*base).ob_type = type_ob; - let self_ = base as *mut SliceBox; - (*self_).inner = Box::into_raw(box_); - &*self_ + pub(crate) fn new(value: Box<[T]>) -> Self { + SliceBox { + data: Box::into_raw(value), + } } - pub(crate) fn data(&self) -> *mut c_void { - self.inner as *mut c_void +} + +impl Drop for SliceBox { + fn drop(&mut self) { + let _boxed_slice = unsafe { Box::from_raw(self.data) }; } } -impl type_object::PyTypeInfo for SliceBox { +impl PyClassAlloc for SliceBox {} + +impl PyClass for SliceBox { + type Dict = PyClassDummySlot; + type WeakRef = PyClassDummySlot; + type BaseNativeType = PyAny; +} + +unsafe impl type_object::PyTypeInfo for SliceBox { type Type = (); type BaseType = PyAny; + type BaseLayout = pyo3::pycell::PyCellBase; + type Layout = PyCell; + type Initializer = PyClassInitializer; + type AsRefTarget = PyCell; const NAME: &'static str = "SliceBox"; const MODULE: Option<&'static str> = Some("_rust_numpy"); - const DESCRIPTION: &'static str = "Memory store for PyArray using rust's Box<[T]>."; + const DESCRIPTION: &'static str = "Memory store for PyArray using rust's Box<[T]> \0"; const FLAGS: usize = 0; - const SIZE: usize = std::mem::size_of::(); - const OFFSET: isize = 0; + #[inline] - unsafe fn type_object() -> &'static mut ffi::PyTypeObject { - static mut TYPE_OBJECT: ::pyo3::ffi::PyTypeObject = ::pyo3::ffi::PyTypeObject_INIT; - &mut TYPE_OBJECT + fn type_object() -> &'static ffi::PyTypeObject { + use pyo3::type_object::LazyStaticType; + static TYPE_OBJECT: LazyStaticType = LazyStaticType::new(); + TYPE_OBJECT.get_or_init::() } } @@ -46,24 +54,3 @@ impl PyMethodsProtocol for SliceBox { Vec::new() } } - -impl AsPyPointer for SliceBox { - #[inline] - fn as_ptr(&self) -> *mut ffi::PyObject { - &self.ob_base as *const _ as *mut _ - } -} - -impl PyObjectAlloc for SliceBox { - /// Calls the rust destructor for the object. - unsafe fn drop(py: Python<'_>, obj: *mut ffi::PyObject) { - let data = (*(obj as *mut SliceBox)).inner; - let boxed_slice = Box::from_raw(data); - drop(boxed_slice); - ::BaseType::drop(py, obj); - } - unsafe fn dealloc(py: Python<'_>, obj: *mut ffi::PyObject) { - Self::drop(py, obj); - ffi::PyObject_Free(obj as *mut c_void); - } -} diff --git a/tests/array.rs b/tests/array.rs index 6a4732a6e..7b1e45817 100644 --- a/tests/array.rs +++ b/tests/array.rs @@ -17,7 +17,7 @@ fn not_contiguous_array<'py>(py: Python<'py>) -> &'py PyArray1 { None, ) .unwrap() - .downcast_ref() + .downcast() .unwrap() }