Introduce PyInternalCaster

This commit is contained in:
kngwyu 2019-12-14 23:16:39 +09:00
parent 4d7dfafe2b
commit a6639076b9
20 changed files with 165 additions and 167 deletions

View file

@ -65,7 +65,7 @@ impl<'a> FnSpec<'a> {
ref pat, ref ty, .. ref pat, ref ty, ..
}) => { }) => {
// skip first argument (cls) // skip first argument (cls)
if (fn_type == FnType::FnClass || fn_type == FnType::FnNew) && !has_self { if fn_type == FnType::FnClass && !has_self {
has_self = true; has_self = true;
continue; continue;
} }

View file

@ -35,10 +35,10 @@ macro_rules! py_unary_pyref_func {
where where
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
use $crate::{pyclass::PyClassShell, FromPyPointer}; use $crate::pyclass::PyClassShell;
let py = $crate::Python::assume_gil_acquired(); let py = $crate::Python::assume_gil_acquired();
let _pool = $crate::GILPool::new(py); let _pool = $crate::GILPool::new(py);
let slf: &mut PyClassShell<T> = FromPyPointer::from_borrowed_ptr_or_panic(py, slf); let slf: &mut PyClassShell<T> = &mut *(slf as *mut PyClassShell<T>);
let res = $class::$f(slf).into(); let res = $class::$f(slf).into();
$crate::callback::cb_convert($conv, py, res) $crate::callback::cb_convert($conv, py, res)
} }

View file

@ -3,7 +3,7 @@
//! Conversions between various states of rust and python types and their wrappers. //! Conversions between various states of rust and python types and their wrappers.
use crate::err::{self, PyDowncastError, PyResult}; use crate::err::{self, PyDowncastError, PyResult};
use crate::object::PyObject; use crate::object::PyObject;
use crate::type_object::PyTypeInfo; use crate::type_object::{PyConcreteObject, PyTypeInfo};
use crate::types::PyAny; use crate::types::PyAny;
use crate::types::PyTuple; use crate::types::PyTuple;
use crate::{ffi, gil, Py, Python}; use crate::{ffi, gil, Py, Python};
@ -393,15 +393,13 @@ where
#[inline] #[inline]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v T { unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v T {
let value = value.into(); let value = value.into();
let ptr = value as *const _ as *const u8 as *const T; T::ConcreteLayout::internal_ref_cast(value)
&*ptr
} }
#[inline] #[inline]
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut T { unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut T {
let value = value.into(); let value = value.into();
let ptr = value as *const _ as *mut u8 as *mut T; T::ConcreteLayout::internal_mut_cast(value)
&mut *ptr
} }
} }
@ -453,10 +451,11 @@ where
T: PyTypeInfo, T: PyTypeInfo,
{ {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_owned(py, p))) NonNull::new(ptr).map(|p| T::ConcreteLayout::internal_ref_cast(gil::register_owned(py, p)))
} }
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_borrowed(py, p))) NonNull::new(ptr)
.map(|p| T::ConcreteLayout::internal_ref_cast(gil::register_borrowed(py, p)))
} }
} }
@ -465,10 +464,11 @@ where
T: PyTypeInfo, T: PyTypeInfo,
{ {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_owned(py, p))) NonNull::new(ptr).map(|p| T::ConcreteLayout::internal_mut_cast(gil::register_owned(py, p)))
} }
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_borrowed(py, p))) NonNull::new(ptr)
.map(|p| T::ConcreteLayout::internal_mut_cast(gil::register_borrowed(py, p)))
} }
} }

View file

@ -1,11 +1,10 @@
// Copyright (c) 2017-present PyO3 Project and Contributors // Copyright (c) 2017-present PyO3 Project and Contributors
use crate::err::{PyErr, PyResult}; use crate::err::{PyErr, PyResult};
use crate::gil; use crate::gil;
use crate::instance;
use crate::object::PyObject; use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol; use crate::objectprotocol::ObjectProtocol;
use crate::pyclass::{PyClass, PyClassShell}; use crate::pyclass::{PyClass, PyClassShell};
use crate::type_object::PyTypeInfo; use crate::type_object::{PyConcreteObject, PyTypeInfo};
use crate::types::PyAny; use crate::types::PyAny;
use crate::{ffi, IntoPy}; use crate::{ffi, IntoPy};
use crate::{AsPyPointer, FromPyObject, IntoPyPointer, Python, ToPyObject}; use crate::{AsPyPointer, FromPyObject, IntoPyPointer, Python, ToPyObject};
@ -36,11 +35,6 @@ unsafe impl<T> Sync for Py<T> {}
impl<T> Py<T> { impl<T> Py<T> {
/// Create new instance of T and move it under python management /// Create new instance of T and move it under python management
///
/// **NOTE**
/// This method's `where` bound is actually the same as `PyClass`.
/// However, since Rust still doesn't have higher order generics, we cannot represent
/// this bound by `PyClass`.
pub fn new(py: Python, value: T) -> PyResult<Py<T>> pub fn new(py: Python, value: T) -> PyResult<Py<T>>
where where
T: PyClass, T: PyClass,
@ -128,7 +122,8 @@ pub trait AsPyRef<T: PyTypeInfo>: Sized {
impl<T: PyTypeInfo> AsPyRef<T> for Py<T> { impl<T: PyTypeInfo> AsPyRef<T> for Py<T> {
fn as_ref(&self, _py: Python) -> &T { fn as_ref(&self, _py: Python) -> &T {
unsafe { &*(self as *const instance::Py<T> as *const T) } let any = self as *const Py<T> as *const PyAny;
unsafe { T::ConcreteLayout::internal_ref_cast(&*any) }
} }
} }
@ -143,8 +138,8 @@ impl<T> IntoPy<PyObject> for Py<T> {
/// Converts `Py` instance -> PyObject. /// Converts `Py` instance -> PyObject.
/// Consumes `self` without calling `Py_DECREF()` /// Consumes `self` without calling `Py_DECREF()`
#[inline] #[inline]
fn into_py(self, py: Python) -> PyObject { fn into_py(self, _py: Python) -> PyObject {
unsafe { PyObject::from_owned_ptr(py, self.into_ptr()) } unsafe { PyObject::from_not_null(self.into_non_null()) }
} }
} }
@ -161,9 +156,25 @@ impl<T> IntoPyPointer for Py<T> {
#[inline] #[inline]
#[must_use] #[must_use]
fn into_ptr(self) -> *mut ffi::PyObject { fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.0.as_ptr(); self.into_non_null().as_ptr()
std::mem::forget(self); }
ptr }
impl<'a, T> std::convert::From<&PyClassShell<T>> for Py<T>
where
T: PyClass,
{
fn from(shell: &PyClassShell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
}
}
impl<'a, T> std::convert::From<&mut PyClassShell<T>> for Py<T>
where
T: PyClass,
{
fn from(shell: &mut PyClassShell<T>) -> Self {
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
} }
} }

View file

@ -3,6 +3,7 @@ use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject}; use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{type_flags, PyConcreteObject, PyTypeObject}; use crate::type_object::{type_flags, PyConcreteObject, PyTypeObject};
use crate::types::PyAny;
use crate::{class, ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python}; use crate::{class, ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use std::ffi::CString; use std::ffi::CString;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
@ -112,7 +113,15 @@ impl<T: PyClass> PyClassShell<T> {
} }
} }
impl<T: PyClass> PyConcreteObject for PyClassShell<T> { impl<T: PyClass> PyConcreteObject<T> for PyClassShell<T> {
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
let shell = obj.as_ptr() as *const PyClassShell<T>;
&*(*shell).pyclass
}
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
let shell = obj.as_ptr() as *const PyClassShell<T> as *mut PyClassShell<T>;
&mut *(*shell).pyclass
}
unsafe fn py_drop(&mut self, py: Python) { unsafe fn py_drop(&mut self, py: Python) {
ManuallyDrop::drop(&mut self.pyclass); ManuallyDrop::drop(&mut self.pyclass);
self.dict.clear_dict(py); self.dict.clear_dict(py);
@ -121,6 +130,12 @@ impl<T: PyClass> PyConcreteObject for PyClassShell<T> {
} }
} }
impl<T: PyClass> AsPyPointer for PyClassShell<T> {
fn as_ptr(&self) -> *mut ffi::PyObject {
(self as *const _) as *mut _
}
}
impl<T: PyClass> std::ops::Deref for PyClassShell<T> { impl<T: PyClass> std::ops::Deref for PyClassShell<T> {
type Target = T; type Target = T;
fn deref(&self) -> &T { fn deref(&self) -> &T {
@ -134,7 +149,13 @@ impl<T: PyClass> std::ops::DerefMut for PyClassShell<T> {
} }
} }
impl<T: PyClass> ToPyObject for PyClassShell<T> { impl<T: PyClass> ToPyObject for &PyClassShell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
}
impl<T: PyClass> ToPyObject for &mut PyClassShell<T> {
fn to_object(&self, py: Python<'_>) -> PyObject { fn to_object(&self, py: Python<'_>) -> PyObject {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) } unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
} }
@ -145,10 +166,11 @@ where
T: PyClass, T: PyClass,
{ {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &**(gil::register_owned(py, p) as *const _ as *const Self)) NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyClassShell<T>))
} }
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &**(gil::register_borrowed(py, p) as *const _ as *const Self)) NonNull::new(ptr)
.map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell<T>))
} }
} }
@ -157,10 +179,14 @@ where
T: PyClass, T: PyClass,
{ {
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &mut **(gil::register_owned(py, p) as *const _ as *mut Self)) NonNull::new(ptr).map(|p| {
&mut *(gil::register_owned(py, p).as_ptr() as *const PyClassShell<T> as *mut _)
})
} }
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> { unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
NonNull::new(ptr).map(|p| &mut **(gil::register_borrowed(py, p) as *const _ as *mut Self)) NonNull::new(ptr).map(|p| {
&mut *(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell<T> as *mut _)
})
} }
} }

View file

@ -7,7 +7,7 @@ use crate::ffi;
use crate::gil::{self, GILGuard}; use crate::gil::{self, GILGuard};
use crate::instance::AsPyRef; use crate::instance::AsPyRef;
use crate::object::PyObject; use crate::object::PyObject;
use crate::type_object::{PyTypeInfo, PyTypeObject}; use crate::type_object::{PyConcreteObject, PyTypeInfo, PyTypeObject};
use crate::types::{PyAny, PyDict, PyModule, PyType}; use crate::types::{PyAny, PyDict, PyModule, PyType};
use crate::AsPyPointer; use crate::AsPyPointer;
use crate::{FromPyPointer, IntoPyPointer, PyTryFrom}; use crate::{FromPyPointer, IntoPyPointer, PyTryFrom};
@ -272,16 +272,6 @@ impl<'p> Python<'p> {
} }
impl<'p> Python<'p> { impl<'p> Python<'p> {
// TODO(kngwyu): Now offset dies, so what should this functions do
pub(crate) unsafe fn unchecked_downcast<T: PyTypeInfo>(self, ob: &PyAny) -> &'p T {
&*(ob as *const _ as *const T)
}
#[allow(clippy::cast_ref_to_mut)] // FIXME
pub(crate) unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(self, ob: &PyAny) -> &'p mut T {
&mut *(ob as *const _ as *mut T)
}
/// Register object in release pool, and try to downcast to specific type. /// Register object in release pool, and try to downcast to specific type.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError> pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
where where
@ -297,7 +287,7 @@ impl<'p> Python<'p> {
T: PyTypeInfo, T: PyTypeInfo,
{ {
let p = gil::register_owned(self, obj.into_nonnull()); let p = gil::register_owned(self, obj.into_nonnull());
self.unchecked_downcast(p) T::ConcreteLayout::internal_ref_cast(p)
} }
/// Register `ffi::PyObject` pointer in release pool /// Register `ffi::PyObject` pointer in release pool

View file

@ -4,6 +4,7 @@
use crate::ffi; use crate::ffi;
use crate::instance::Py; use crate::instance::Py;
use crate::instance::PyNativeType;
use crate::types::PyAny; use crate::types::PyAny;
use crate::types::PyType; use crate::types::PyType;
use crate::AsPyPointer; use crate::AsPyPointer;
@ -11,17 +12,17 @@ use crate::Python;
use std::ptr::NonNull; use std::ptr::NonNull;
/// TODO: write document /// TODO: write document
pub trait PyConcreteObject: Sized { pub trait PyConcreteObject<T>: Sized {
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
&*(obj as *const _ as *const T)
}
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
&mut *(obj as *const _ as *const T as *mut T)
}
unsafe fn py_drop(&mut self, _py: Python) {} unsafe fn py_drop(&mut self, _py: Python) {}
} }
impl<T: PyConcreteObject> AsPyPointer for T { impl<T: PyNativeType> PyConcreteObject<T> for ffi::PyObject {}
fn as_ptr(&self) -> *mut ffi::PyObject {
(self as *const _) as _
}
}
impl PyConcreteObject for ffi::PyObject {}
/// Our custom type flags /// Our custom type flags
pub mod type_flags { pub mod type_flags {
@ -39,7 +40,7 @@ pub mod type_flags {
} }
/// Python type information. /// Python type information.
pub trait PyTypeInfo { pub trait PyTypeInfo: Sized {
/// Type of objects to store in PyObject struct /// Type of objects to store in PyObject struct
type Type; type Type;
@ -59,7 +60,7 @@ pub trait PyTypeInfo {
type BaseType: PyTypeInfo; type BaseType: PyTypeInfo;
/// Layout /// Layout
type ConcreteLayout: PyConcreteObject; type ConcreteLayout: PyConcreteObject<Self>;
/// PyTypeObject instance for this type, which might still need to /// PyTypeObject instance for this type, which might still need to
/// be initialized /// be initialized

View file

@ -1,6 +1,6 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py_run; use pyo3::py_run;
use pyo3::type_object::initialize_type; use pyo3::pyclass::initialize_type;
mod common; mod common;

View file

@ -1,5 +1,4 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::PyRawObject;
#[pyclass] #[pyclass]
struct EmptyClassWithNew {} struct EmptyClassWithNew {}
@ -7,8 +6,8 @@ struct EmptyClassWithNew {}
#[pymethods] #[pymethods]
impl EmptyClassWithNew { impl EmptyClassWithNew {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> EmptyClassWithNew {
obj.init(EmptyClassWithNew {}); EmptyClassWithNew {}
} }
} }
@ -25,6 +24,7 @@ fn empty_class_with_new() {
} }
#[pyclass] #[pyclass]
#[derive(Debug)]
struct NewWithOneArg { struct NewWithOneArg {
_data: i32, _data: i32,
} }
@ -32,8 +32,8 @@ struct NewWithOneArg {
#[pymethods] #[pymethods]
impl NewWithOneArg { impl NewWithOneArg {
#[new] #[new]
fn new(obj: &PyRawObject, arg: i32) { fn new(arg: i32) -> NewWithOneArg {
obj.init(NewWithOneArg { _data: arg }) NewWithOneArg { _data: arg }
} }
} }
@ -56,11 +56,11 @@ struct NewWithTwoArgs {
#[pymethods] #[pymethods]
impl NewWithTwoArgs { impl NewWithTwoArgs {
#[new] #[new]
fn new(obj: &PyRawObject, arg1: i32, arg2: i32) { fn new(arg1: i32, arg2: i32) -> Self {
obj.init(NewWithTwoArgs { NewWithTwoArgs {
_data1: arg1, _data1: arg1,
_data2: arg2, _data2: arg2,
}) }
} }
} }

0
tests/test_datetime.rs Normal file → Executable file
View file

View file

@ -4,11 +4,9 @@ use pyo3::class::{
PyContextProtocol, PyIterProtocol, PyMappingProtocol, PyObjectProtocol, PySequenceProtocol, PyContextProtocol, PyIterProtocol, PyMappingProtocol, PyObjectProtocol, PySequenceProtocol,
}; };
use pyo3::exceptions::{IndexError, ValueError}; use pyo3::exceptions::{IndexError, ValueError};
use pyo3::ffi;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType}; use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType};
use pyo3::AsPyPointer; use pyo3::{ffi, py_run, AsPyPointer, PyClassShell};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::{isize, iter}; use std::{isize, iter};
@ -55,11 +53,11 @@ struct Iterator {
#[pyproto] #[pyproto]
impl<'p> PyIterProtocol for Iterator { impl<'p> PyIterProtocol for Iterator {
fn __iter__(slf: PyRefMut<Self>) -> PyResult<Py<Iterator>> { fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<Py<Iterator>> {
Ok(slf.into()) Ok(slf.into())
} }
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<i32>> { fn __next__(mut slf: &mut PyClassShell<Self>) -> PyResult<Option<i32>> {
Ok(slf.iter.next()) Ok(slf.iter.next())
} }
} }
@ -252,7 +250,7 @@ fn setitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let c = PyRef::new(py, SetItem { key: 0, val: 0 }).unwrap(); let c = PyClassShell::new_ref(py, SetItem { key: 0, val: 0 }).unwrap();
py_run!(py, c, "c[1] = 2"); py_run!(py, c, "c[1] = 2");
assert_eq!(c.key, 1); assert_eq!(c.key, 1);
assert_eq!(c.val, 2); assert_eq!(c.val, 2);
@ -277,7 +275,7 @@ fn delitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let c = PyRef::new(py, DelItem { key: 0 }).unwrap(); let c = PyClassShell::new_ref(py, DelItem { key: 0 }).unwrap();
py_run!(py, c, "del c[1]"); py_run!(py, c, "del c[1]");
assert_eq!(c.key, 1); assert_eq!(c.key, 1);
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError); py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
@ -306,7 +304,7 @@ fn setdelitem() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let c = PyRef::new(py, SetDelItem { val: None }).unwrap(); let c = PyClassShell::new_ref(py, SetDelItem { val: None }).unwrap();
py_run!(py, c, "c[1] = 2"); py_run!(py, c, "c[1] = 2");
assert_eq!(c.val, Some(2)); assert_eq!(c.val, Some(2));
py_run!(py, c, "del c[1]"); py_run!(py, c, "del c[1]");
@ -385,7 +383,7 @@ fn context_manager() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let mut c = PyRefMut::new(py, ContextManager { exit_called: false }).unwrap(); let c = PyClassShell::new_mut(py, ContextManager { exit_called: false }).unwrap();
py_run!(py, c, "with c as x: assert x == 42"); py_run!(py, c, "with c as x: assert x == 42");
assert!(c.exit_called); assert!(c.exit_called);
@ -457,7 +455,7 @@ struct DunderDictSupport {}
fn dunder_dict_support() { fn dunder_dict_support() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, DunderDictSupport {}).unwrap(); let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!( py_run!(
py, py,
inst, inst,
@ -472,7 +470,7 @@ fn dunder_dict_support() {
fn access_dunder_dict() { fn access_dunder_dict() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, DunderDictSupport {}).unwrap(); let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!( py_run!(
py, py,
inst, inst,
@ -490,7 +488,7 @@ struct WeakRefDunderDictSupport {}
fn weakref_dunder_dict_support() { fn weakref_dunder_dict_support() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, WeakRefDunderDictSupport {}).unwrap(); let inst = PyClassShell::new_ref(py, WeakRefDunderDictSupport {}).unwrap();
py_run!( py_run!(
py, py,
inst, inst,
@ -515,7 +513,7 @@ impl PyObjectProtocol for ClassWithGetAttr {
fn getattr_doesnt_override_member() { fn getattr_doesnt_override_member() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, ClassWithGetAttr { data: 4 }).unwrap(); let inst = PyClassShell::new_ref(py, ClassWithGetAttr { data: 4 }).unwrap();
py_assert!(py, inst, "inst.data == 4"); py_assert!(py, inst, "inst.data == 4");
py_assert!(py, inst, "inst.a == 8"); py_assert!(py, inst, "inst.a == 8");
} }

View file

@ -1,13 +1,9 @@
use pyo3::class::PyGCProtocol; use pyo3::class::PyGCProtocol;
use pyo3::class::PyTraverseError; use pyo3::class::PyTraverseError;
use pyo3::class::PyVisit; use pyo3::class::PyVisit;
use pyo3::ffi;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py_run; use pyo3::types::{PyAny, PyTuple};
use pyo3::types::PyAny; use pyo3::{ffi, py_run, AsPyPointer, PyClassShell};
use pyo3::types::PyTuple;
use pyo3::AsPyPointer;
use pyo3::PyRawObject;
use std::cell::RefCell; use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -157,7 +153,7 @@ fn gc_integration() {
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new( let inst = PyClassShell::new_mut(
py, py,
GCIntegration { GCIntegration {
self_ref: RefCell::new(py.None()), self_ref: RefCell::new(py.None()),
@ -192,7 +188,7 @@ impl PyGCProtocol for GCIntegration2 {
fn gc_integration2() { fn gc_integration2() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, GCIntegration2 {}).unwrap(); let inst = PyClassShell::new_ref(py, GCIntegration2 {}).unwrap();
py_run!(py, inst, "import gc; assert inst in gc.get_objects()"); py_run!(py, inst, "import gc; assert inst in gc.get_objects()");
} }
@ -203,7 +199,7 @@ struct WeakRefSupport {}
fn weakref_support() { fn weakref_support() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let inst = PyRef::new(py, WeakRefSupport {}).unwrap(); let inst = PyClassShell::new_ref(py, WeakRefSupport {}).unwrap();
py_run!( py_run!(
py, py,
inst, inst,
@ -219,8 +215,8 @@ struct BaseClassWithDrop {
#[pymethods] #[pymethods]
impl BaseClassWithDrop { impl BaseClassWithDrop {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> BaseClassWithDrop {
obj.init(BaseClassWithDrop { data: None }) BaseClassWithDrop { data: None }
} }
} }
@ -239,10 +235,10 @@ struct SubClassWithDrop {
#[pymethods] #[pymethods]
impl SubClassWithDrop { impl SubClassWithDrop {
// TODO(kngwyu): Implement baseclass initialization
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> SubClassWithDrop {
obj.init(SubClassWithDrop { data: None }); SubClassWithDrop { data: None }
BaseClassWithDrop::new(obj);
} }
} }

View file

@ -2,7 +2,6 @@ use pyo3::prelude::*;
use pyo3::py_run; use pyo3::py_run;
#[cfg(feature = "unsound-subclass")] #[cfg(feature = "unsound-subclass")]
use pyo3::types::IntoPyDict; use pyo3::types::IntoPyDict;
use std::isize;
mod common; mod common;
@ -35,8 +34,8 @@ fn subclass() {
#[pymethods] #[pymethods]
impl BaseClass { impl BaseClass {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> Self {
obj.init(BaseClass { val1: 10 }) BaseClass { val1: 10 }
} }
} }
@ -49,13 +48,14 @@ struct SubClass {
#[pymethods] #[pymethods]
impl SubClass { impl SubClass {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> Self {
obj.init(SubClass { val2: 5 }); SubClass { val2: 5 }
BaseClass::new(obj);
} }
} }
// TODO(kngwyu): disable untill super().__init__ fixed
#[test] #[test]
#[ignore]
fn inheritance_with_new_methods() { fn inheritance_with_new_methods() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();

9
tests/test_mapping.rs Normal file → Executable file
View file

@ -15,20 +15,19 @@ struct Mapping {
#[pymethods] #[pymethods]
impl Mapping { impl Mapping {
#[new] #[new]
fn new(obj: &PyRawObject, elements: Option<&PyList>) -> PyResult<()> { fn new(elements: Option<&PyList>) -> PyResult<Self> {
if let Some(pylist) = elements { if let Some(pylist) = elements {
let mut elems = HashMap::with_capacity(pylist.len()); let mut elems = HashMap::with_capacity(pylist.len());
for (i, pyelem) in pylist.into_iter().enumerate() { for (i, pyelem) in pylist.into_iter().enumerate() {
let elem = String::extract(pyelem)?; let elem = String::extract(pyelem)?;
elems.insert(elem, i); elems.insert(elem, i);
} }
obj.init(Self { index: elems }); Ok(Self { index: elems })
} else { } else {
obj.init(Self { Ok(Self {
index: HashMap::new(), index: HashMap::new(),
}); })
} }
Ok(())
} }
} }

View file

@ -1,7 +1,7 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::py_run; use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType}; use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType};
use pyo3::PyRawObject; use pyo3::PyClassShell;
mod common; mod common;
@ -23,7 +23,7 @@ fn instance_method() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let obj = PyRefMut::new(py, InstanceMethod { member: 42 }).unwrap(); let obj = PyClassShell::new_mut(py, InstanceMethod { member: 42 }).unwrap();
assert_eq!(obj.method().unwrap(), 42); assert_eq!(obj.method().unwrap(), 42);
let d = [("obj", obj)].into_py_dict(py); let d = [("obj", obj)].into_py_dict(py);
py.run("assert obj.method() == 42", None, Some(d)).unwrap(); py.run("assert obj.method() == 42", None, Some(d)).unwrap();
@ -49,7 +49,7 @@ fn instance_method_with_args() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let obj = PyRefMut::new(py, InstanceMethodWithArgs { member: 7 }).unwrap(); let obj = PyClassShell::new_mut(py, InstanceMethodWithArgs { member: 7 }).unwrap();
assert_eq!(obj.method(6).unwrap(), 42); assert_eq!(obj.method(6).unwrap(), 42);
let d = [("obj", obj)].into_py_dict(py); let d = [("obj", obj)].into_py_dict(py);
py.run("assert obj.method(3) == 21", None, Some(d)).unwrap(); py.run("assert obj.method(3) == 21", None, Some(d)).unwrap();
@ -63,8 +63,8 @@ struct ClassMethod {}
#[pymethods] #[pymethods]
impl ClassMethod { impl ClassMethod {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> Self {
obj.init(ClassMethod {}) ClassMethod {}
} }
#[classmethod] #[classmethod]
@ -137,8 +137,8 @@ struct StaticMethod {}
#[pymethods] #[pymethods]
impl StaticMethod { impl StaticMethod {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> Self {
obj.init(StaticMethod {}) StaticMethod {}
} }
#[staticmethod] #[staticmethod]
@ -395,7 +395,7 @@ impl MethodWithLifeTime {
fn method_with_lifetime() { fn method_with_lifetime() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let obj = PyRef::new(py, MethodWithLifeTime {}).unwrap(); let obj = PyClassShell::new_ref(py, MethodWithLifeTime {}).unwrap();
py_run!( py_run!(
py, py,
obj, obj,

View file

@ -1,26 +0,0 @@
use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::pyclass::PyClassShell;
use pyo3::types::PyAny;
use pyo3::FromPyPointer;
#[pyclass]
struct Class {
member: i32,
}
#[pymethods]
impl Class {
fn hello(&self) -> i32 {
self.member
}
}
#[test]
fn test_shell() {
let class = Class { member: 128 };
let gil = Python::acquire_gil();
let py = gil.python();
// let obj: &PyAny = unsafe { FromPyPointer::from_owned_ptr(py, PyClassShell::new(py, class)) };
// py_run!(py, obj, "assert obj.hello() == 128");
}

View file

@ -2,7 +2,7 @@
use pyo3; use pyo3;
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::types::{PyBytes, PyString}; use pyo3::types::{PyBytes, PyString};
use pyo3::PyIterProtocol; use pyo3::{AsPyRef, PyClassShell, PyIterProtocol};
use std::collections::HashMap; use std::collections::HashMap;
mod common; mod common;
@ -10,20 +10,23 @@ mod common;
/// Assumes it's a file reader or so. /// Assumes it's a file reader or so.
/// Inspired by https://github.com/jothan/cordoba, thanks. /// Inspired by https://github.com/jothan/cordoba, thanks.
#[pyclass] #[pyclass]
#[derive(Clone)] #[derive(Clone, Debug)]
struct Reader { struct Reader {
inner: HashMap<u8, String>, inner: HashMap<u8, String>,
} }
#[pymethods] #[pymethods]
impl Reader { impl Reader {
fn clone_ref(slf: PyRef<Self>) -> PyRef<Self> { fn clone_ref(slf: &PyClassShell<Self>) -> &PyClassShell<Self> {
slf slf
} }
fn clone_ref_with_py<'py>(slf: PyRef<'py, Self>, _py: Python<'py>) -> PyRef<'py, Self> { fn clone_ref_with_py<'py>(
slf: &'py PyClassShell<Self>,
_py: Python<'py>,
) -> &'py PyClassShell<Self> {
slf slf
} }
fn get_iter(slf: PyRef<Self>, keys: Py<PyBytes>) -> PyResult<Iter> { fn get_iter(slf: &PyClassShell<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
Ok(Iter { Ok(Iter {
reader: slf.into(), reader: slf.into(),
keys, keys,
@ -31,7 +34,7 @@ impl Reader {
}) })
} }
fn get_iter_and_reset( fn get_iter_and_reset(
mut slf: PyRefMut<Self>, slf: &mut PyClassShell<Self>,
keys: Py<PyBytes>, keys: Py<PyBytes>,
py: Python, py: Python,
) -> PyResult<Iter> { ) -> PyResult<Iter> {
@ -54,13 +57,15 @@ struct Iter {
#[pyproto] #[pyproto]
impl PyIterProtocol for Iter { impl PyIterProtocol for Iter {
fn __iter__(slf: PyRefMut<Self>) -> PyResult<PyObject> { fn __iter__(slf: &mut PyClassShell<Self>) -> PyResult<PyObject> {
let py = unsafe { Python::assume_gil_acquired() }; let py = unsafe { Python::assume_gil_acquired() };
Ok(slf.to_object(py)) Ok(slf.to_object(py))
} }
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<PyObject>> {
fn __next__(slf: &mut PyClassShell<Self>) -> PyResult<Option<PyObject>> {
let py = unsafe { Python::assume_gil_acquired() }; let py = unsafe { Python::assume_gil_acquired() };
match slf.keys.as_ref(py).as_bytes().get(slf.idx) { let bytes = slf.keys.as_ref(py).as_bytes();
match bytes.get(slf.idx) {
Some(&b) => { Some(&b) => {
let res = slf let res = slf
.reader .reader
@ -84,7 +89,7 @@ fn reader() -> Reader {
} }
#[test] #[test]
fn test_nested_iter() { fn test_nested_iter1() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let reader: PyObject = reader().into_py(py); let reader: PyObject = reader().into_py(py);
@ -108,7 +113,7 @@ fn test_clone_ref() {
fn test_nested_iter_reset() { fn test_nested_iter_reset() {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
let reader = PyRef::new(py, reader()).unwrap(); let reader = PyClassShell::new_ref(py, reader()).unwrap();
py_assert!( py_assert!(
py, py,
reader, reader,

View file

@ -14,20 +14,19 @@ struct ByteSequence {
#[pymethods] #[pymethods]
impl ByteSequence { impl ByteSequence {
#[new] #[new]
fn new(obj: &PyRawObject, elements: Option<&PyList>) -> PyResult<()> { fn new(elements: Option<&PyList>) -> PyResult<Self> {
if let Some(pylist) = elements { if let Some(pylist) = elements {
let mut elems = Vec::with_capacity(pylist.len()); let mut elems = Vec::with_capacity(pylist.len());
for pyelem in pylist.into_iter() { for pyelem in pylist.into_iter() {
let elem = u8::extract(pyelem)?; let elem = u8::extract(pyelem)?;
elems.push(elem); elems.push(elem);
} }
obj.init(Self { elements: elems }); Ok(Self { elements: elems })
} else { } else {
obj.init(Self { Ok(Self {
elements: Vec::new(), elements: Vec::new(),
}); })
} }
Ok(())
} }
} }

View file

@ -1,5 +1,5 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::{types::PyType, wrap_pyfunction, wrap_pymodule}; use pyo3::{types::PyType, wrap_pyfunction, wrap_pymodule, PyClassShell};
mod common; mod common;
@ -44,9 +44,9 @@ fn class_with_docs_and_signature() {
impl MyClass { impl MyClass {
#[new] #[new]
#[args(a, b = "None", "*", c = 42)] #[args(a, b = "None", "*", c = 42)]
fn __new__(obj: &PyRawObject, a: i32, b: Option<i32>, c: i32) { fn __new__(a: i32, b: Option<i32>, c: i32) -> Self {
let _ = (a, b, c); let _ = (a, b, c);
obj.init(Self {}); Self {}
} }
} }
@ -76,9 +76,9 @@ fn class_with_signature() {
impl MyClass { impl MyClass {
#[new] #[new]
#[args(a, b = "None", "*", c = 42)] #[args(a, b = "None", "*", c = 42)]
fn __new__(obj: &PyRawObject, a: i32, b: Option<i32>, c: i32) { fn __new__(a: i32, b: Option<i32>, c: i32) -> Self {
let _ = (a, b, c); let _ = (a, b, c);
obj.init(Self {}); Self {}
} }
} }
@ -144,7 +144,7 @@ fn test_methods() {
let _ = a; let _ = a;
} }
#[text_signature = "($self, b)"] #[text_signature = "($self, b)"]
fn pyself_method(_this: PyRef<Self>, b: i32) { fn pyself_method(_this: &PyClassShell<Self>, b: i32) {
let _ = b; let _ = b;
} }
#[classmethod] #[classmethod]

View file

@ -1,9 +1,8 @@
use pyo3::prelude::*; use pyo3::prelude::*;
use pyo3::type_object::initialize_type; use pyo3::pyclass::initialize_type;
use pyo3::types::IntoPyDict; use pyo3::types::IntoPyDict;
use pyo3::types::{PyDict, PyTuple}; use pyo3::types::{PyDict, PyTuple};
use pyo3::{py_run, wrap_pyfunction}; use pyo3::{py_run, wrap_pyfunction, AsPyRef, PyClassShell};
use std::isize;
mod common; mod common;
@ -83,8 +82,8 @@ fn intopytuple_pyclass() {
let py = gil.python(); let py = gil.python();
let tup = ( let tup = (
PyRef::new(py, SimplePyClass {}).unwrap(), PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyRef::new(py, SimplePyClass {}).unwrap(), PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
); );
py_assert!(py, tup, "type(tup[0]).__name__ == 'SimplePyClass'"); py_assert!(py, tup, "type(tup[0]).__name__ == 'SimplePyClass'");
py_assert!(py, tup, "type(tup[0]).__name__ == type(tup[1]).__name__"); py_assert!(py, tup, "type(tup[0]).__name__ == type(tup[1]).__name__");
@ -108,8 +107,8 @@ fn pytuple_pyclass_iter() {
let tup = PyTuple::new( let tup = PyTuple::new(
py, py,
[ [
PyRef::new(py, SimplePyClass {}).unwrap(), PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
PyRef::new(py, SimplePyClass {}).unwrap(), PyClassShell::new_ref(py, SimplePyClass {}).unwrap(),
] ]
.iter(), .iter(),
); );
@ -124,12 +123,12 @@ struct PickleSupport {}
#[pymethods] #[pymethods]
impl PickleSupport { impl PickleSupport {
#[new] #[new]
fn new(obj: &PyRawObject) { fn new() -> PickleSupport {
obj.init({ PickleSupport {} }); PickleSupport {}
} }
pub fn __reduce__<'py>( pub fn __reduce__<'py>(
slf: PyRef<Self>, slf: &'py PyClassShell<Self>,
py: Python<'py>, py: Python<'py>,
) -> PyResult<(PyObject, &'py PyTuple, PyObject)> { ) -> PyResult<(PyObject, &'py PyTuple, PyObject)> {
let cls = slf.to_object(py).getattr(py, "__class__")?; let cls = slf.to_object(py).getattr(py, "__class__")?;
@ -155,7 +154,7 @@ fn test_pickle() {
module.add_class::<PickleSupport>().unwrap(); module.add_class::<PickleSupport>().unwrap();
add_module(py, module).unwrap(); add_module(py, module).unwrap();
initialize_type::<PickleSupport>(py, Some("test_module")).unwrap(); initialize_type::<PickleSupport>(py, Some("test_module")).unwrap();
let inst = PyRef::new(py, PickleSupport {}).unwrap(); let inst = PyClassShell::new_ref(py, PickleSupport {}).unwrap();
py_run!( py_run!(
py, py,
inst, inst,