From 8af258bd474b7a4f38bda8bf3188652bb91c0265 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Sun, 19 Jan 2020 18:52:12 +0900 Subject: [PATCH 1/4] Update PyO3 to 0.9.0 --- Cargo.toml | 4 +- README.md | 4 +- examples/linalg/Cargo.toml | 2 +- examples/simple-extension/Cargo.toml | 2 +- src/array.rs | 12 +++-- src/slice_box.rs | 67 +++++++++++----------------- 6 files changed, 41 insertions(+), 50 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9fa72de85..f876f919d 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 = { git = "https://github.com/PyO3/pyo3.git" } [features] # In default setting, python version is automatically detected diff --git a/README.md b/README.md index f41aec7a7..489df86d1 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-alpha.1" 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..9f8596f50 100644 --- a/examples/linalg/Cargo.toml +++ b/examples/linalg/Cargo.toml @@ -14,5 +14,5 @@ ndarray = ">= 0.12" ndarray-linalg = { version = "0.10", features = ["openblas"] } [dependencies.pyo3] -version = "0.8" +version = "0.9.0-alpha.1" features = ["extension-module"] diff --git a/examples/simple-extension/Cargo.toml b/examples/simple-extension/Cargo.toml index 97219fbfd..664a500bd 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-alpha.1" features = ["extension-module"] diff --git a/src/array.rs b/src/array.rs index 05db9b54a..596c5cc97 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) } +impl type_object::PyObjectLayout> for npyffi::PyArrayObject {} +impl type_object::PyObjectSizedLayout> 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, @@ -386,19 +390,19 @@ impl PyArray { ID: IntoDimension, { let dims = dims.into_dimension(); - let slice = SliceBox::new(slice); + let container = SliceBox::new(py, slice).expect("SliceBox 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 + (*container).data 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, container as _); Self::from_owned_ptr(py, ptr) } diff --git a/src/slice_box.rs b/src/slice_box.rs index 6b5c3fb95..2e46b683f 100644 --- a/src/slice_box.rs +++ b/src/slice_box.rs @@ -1,39 +1,47 @@ 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, PyClassShell}; +use pyo3::pyclass_slots::PyClassDummySlot; +use pyo3::{ffi, type_object, types::PyAny, PyClassInitializer, PyResult, Python}; -/// 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) unsafe fn new( + py: Python<'_>, + value: Box<[T]>, + ) -> PyResult<*mut PyClassShell>> { + let value = SliceBox { + data: Box::into_raw(value), + }; + PyClassInitializer::from(value).create_shell(py) } - 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 PyClassAlloc for SliceBox {} + +impl PyClass for SliceBox { + type Dict = PyClassDummySlot; + type WeakRef = PyClassDummySlot; +} + impl type_object::PyTypeInfo for SliceBox { type Type = (); type BaseType = PyAny; + type ConcreteLayout = PyClassShell; + type Initializer = PyClassInitializer; 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 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; @@ -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); - } -} From 919c19e5a16df89deded5b1c71290b7646333c44 Mon Sep 17 00:00:00 2001 From: Masterchef365 Date: Fri, 6 Mar 2020 11:22:58 -0800 Subject: [PATCH 2/4] Switch pyo3 crate version from git to crates.io alpha --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f876f919d..28753f3ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ libc = "0.2" num-complex = "0.2" num-traits = "0.2" ndarray = ">=0.13" -pyo3 = { git = "https://github.com/PyO3/pyo3.git" } +pyo3 = "0.9.0-alpha.1" [features] # In default setting, python version is automatically detected From 3d623448c26be2ec466712225aaa102452eb8ac2 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Mon, 9 Mar 2020 18:34:51 +0900 Subject: [PATCH 3/4] Update for upcoming PyO3 0.9.0 --- Cargo.toml | 2 +- README.md | 2 +- examples/linalg/Cargo.toml | 6 +++--- examples/simple-extension/Cargo.toml | 2 +- src/array.rs | 18 +++++++++++------- src/slice_box.rs | 28 ++++++++++++++-------------- tests/array.rs | 2 +- 7 files changed, 32 insertions(+), 28 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 28753f3ff..d985396e3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ libc = "0.2" num-complex = "0.2" num-traits = "0.2" ndarray = ">=0.13" -pyo3 = "0.9.0-alpha.1" +pyo3 = "0.9.0" [features] # In default setting, python version is automatically detected diff --git a/README.md b/README.md index 489df86d1..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.9.0-alpha.1" +pyo3 = "0.9.0" numpy = "0.7.0" ``` diff --git a/examples/linalg/Cargo.toml b/examples/linalg/Cargo.toml index 9f8596f50..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.9.0-alpha.1" +version = "0.9.0" features = ["extension-module"] diff --git a/examples/simple-extension/Cargo.toml b/examples/simple-extension/Cargo.toml index 664a500bd..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.9.0-alpha.1" +version = "0.9.0" features = ["extension-module"] diff --git a/src/array.rs b/src/array.rs index 596c5cc97..be65aa598 100644 --- a/src/array.rs +++ b/src/array.rs @@ -99,8 +99,8 @@ pub fn get_array_module(py: Python<'_>) -> PyResult<&PyModule> { PyModule::import(py, npyffi::array::MOD_NAME) } -impl type_object::PyObjectLayout> for npyffi::PyArrayObject {} -impl type_object::PyObjectSizedLayout> for npyffi::PyArrayObject {} +unsafe impl type_object::PyLayout> for npyffi::PyArrayObject {} +impl type_object::PySizedLayout> for npyffi::PyArrayObject {} pyobject_native_type_convert!( PyArray, @@ -170,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()); /// # } @@ -390,19 +390,23 @@ impl PyArray { ID: IntoDimension, { let dims = dims.into_dimension(); - let container = SliceBox::new(py, slice).expect("SliceBox creation failed"); + 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 - (*container).data as _, // 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, container as _); + PY_ARRAY_API.PyArray_SetBaseObject(ptr as *mut npyffi::PyArrayObject, cell as _); Self::from_owned_ptr(py, ptr) } @@ -455,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 2e46b683f..3047aa7bb 100644 --- a/src/slice_box.rs +++ b/src/slice_box.rs @@ -1,21 +1,17 @@ use pyo3::class::methods::{PyMethodDefType, PyMethodsProtocol}; -use pyo3::pyclass::{PyClass, PyClassAlloc, PyClassShell}; +use pyo3::pyclass::{PyClass, PyClassAlloc}; use pyo3::pyclass_slots::PyClassDummySlot; -use pyo3::{ffi, type_object, types::PyAny, PyClassInitializer, PyResult, Python}; +use pyo3::{ffi, type_object, types::PyAny, PyCell, PyClassInitializer}; pub(crate) struct SliceBox { pub(crate) data: *mut [T], } impl SliceBox { - pub(crate) unsafe fn new( - py: Python<'_>, - value: Box<[T]>, - ) -> PyResult<*mut PyClassShell>> { - let value = SliceBox { + pub(crate) fn new(value: Box<[T]>) -> Self { + SliceBox { data: Box::into_raw(value), - }; - PyClassInitializer::from(value).create_shell(py) + } } } @@ -30,22 +26,26 @@ impl PyClassAlloc for SliceBox {} impl PyClass for SliceBox { type Dict = PyClassDummySlot; type WeakRef = PyClassDummySlot; + type BaseNativeType = PyAny; } -impl type_object::PyTypeInfo for SliceBox { +unsafe impl type_object::PyTypeInfo for SliceBox { type Type = (); type BaseType = PyAny; - type ConcreteLayout = PyClassShell; + 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 FLAGS: usize = 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::() } } 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() } From ce3a106e9fc960f0ae740bb0e3e59b821b73b297 Mon Sep 17 00:00:00 2001 From: kngwyu Date: Thu, 19 Mar 2020 15:24:36 +0900 Subject: [PATCH 4/4] Make SliceBox::DESCRIPTION null-terminated --- src/slice_box.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/slice_box.rs b/src/slice_box.rs index 3047aa7bb..52fee5b0f 100644 --- a/src/slice_box.rs +++ b/src/slice_box.rs @@ -38,7 +38,7 @@ unsafe impl type_object::PyTypeInfo for SliceBox { 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; #[inline]