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, ..
}) => {
// 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;
continue;
}

View file

@ -35,10 +35,10 @@ macro_rules! py_unary_pyref_func {
where
T: for<'p> $trait<'p>,
{
use $crate::{pyclass::PyClassShell, FromPyPointer};
use $crate::pyclass::PyClassShell;
let py = $crate::Python::assume_gil_acquired();
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();
$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.
use crate::err::{self, PyDowncastError, PyResult};
use crate::object::PyObject;
use crate::type_object::PyTypeInfo;
use crate::type_object::{PyConcreteObject, PyTypeInfo};
use crate::types::PyAny;
use crate::types::PyTuple;
use crate::{ffi, gil, Py, Python};
@ -393,15 +393,13 @@ where
#[inline]
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v T {
let value = value.into();
let ptr = value as *const _ as *const u8 as *const T;
&*ptr
T::ConcreteLayout::internal_ref_cast(value)
}
#[inline]
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut T {
let value = value.into();
let ptr = value as *const _ as *mut u8 as *mut T;
&mut *ptr
T::ConcreteLayout::internal_mut_cast(value)
}
}
@ -453,10 +451,11 @@ where
T: PyTypeInfo,
{
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> {
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,
{
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> {
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
use crate::err::{PyErr, PyResult};
use crate::gil;
use crate::instance;
use crate::object::PyObject;
use crate::objectprotocol::ObjectProtocol;
use crate::pyclass::{PyClass, PyClassShell};
use crate::type_object::PyTypeInfo;
use crate::type_object::{PyConcreteObject, PyTypeInfo};
use crate::types::PyAny;
use crate::{ffi, IntoPy};
use crate::{AsPyPointer, FromPyObject, IntoPyPointer, Python, ToPyObject};
@ -36,11 +35,6 @@ unsafe impl<T> Sync for Py<T> {}
impl<T> Py<T> {
/// 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>>
where
T: PyClass,
@ -128,7 +122,8 @@ pub trait AsPyRef<T: PyTypeInfo>: Sized {
impl<T: PyTypeInfo> AsPyRef<T> for Py<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.
/// Consumes `self` without calling `Py_DECREF()`
#[inline]
fn into_py(self, py: Python) -> PyObject {
unsafe { PyObject::from_owned_ptr(py, self.into_ptr()) }
fn into_py(self, _py: Python) -> PyObject {
unsafe { PyObject::from_not_null(self.into_non_null()) }
}
}
@ -161,9 +156,25 @@ impl<T> IntoPyPointer for Py<T> {
#[inline]
#[must_use]
fn into_ptr(self) -> *mut ffi::PyObject {
let ptr = self.0.as_ptr();
std::mem::forget(self);
ptr
self.into_non_null().as_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::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{type_flags, PyConcreteObject, PyTypeObject};
use crate::types::PyAny;
use crate::{class, ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
use std::ffi::CString;
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) {
ManuallyDrop::drop(&mut self.pyclass);
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> {
type Target = 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 {
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
}
@ -145,10 +166,11 @@ where
T: PyClass,
{
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> {
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,
{
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> {
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::instance::AsPyRef;
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::AsPyPointer;
use crate::{FromPyPointer, IntoPyPointer, PyTryFrom};
@ -272,16 +272,6 @@ 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.
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
where
@ -297,7 +287,7 @@ impl<'p> Python<'p> {
T: PyTypeInfo,
{
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

View file

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

View file

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

View file

@ -1,5 +1,4 @@
use pyo3::prelude::*;
use pyo3::PyRawObject;
#[pyclass]
struct EmptyClassWithNew {}
@ -7,8 +6,8 @@ struct EmptyClassWithNew {}
#[pymethods]
impl EmptyClassWithNew {
#[new]
fn new(obj: &PyRawObject) {
obj.init(EmptyClassWithNew {});
fn new() -> EmptyClassWithNew {
EmptyClassWithNew {}
}
}
@ -25,6 +24,7 @@ fn empty_class_with_new() {
}
#[pyclass]
#[derive(Debug)]
struct NewWithOneArg {
_data: i32,
}
@ -32,8 +32,8 @@ struct NewWithOneArg {
#[pymethods]
impl NewWithOneArg {
#[new]
fn new(obj: &PyRawObject, arg: i32) {
obj.init(NewWithOneArg { _data: arg })
fn new(arg: i32) -> NewWithOneArg {
NewWithOneArg { _data: arg }
}
}
@ -56,11 +56,11 @@ struct NewWithTwoArgs {
#[pymethods]
impl NewWithTwoArgs {
#[new]
fn new(obj: &PyRawObject, arg1: i32, arg2: i32) {
obj.init(NewWithTwoArgs {
fn new(arg1: i32, arg2: i32) -> Self {
NewWithTwoArgs {
_data1: arg1,
_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,
};
use pyo3::exceptions::{IndexError, ValueError};
use pyo3::ffi;
use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyAny, PyBytes, PySlice, PyType};
use pyo3::AsPyPointer;
use pyo3::{ffi, py_run, AsPyPointer, PyClassShell};
use std::convert::TryFrom;
use std::{isize, iter};
@ -55,11 +53,11 @@ struct Iterator {
#[pyproto]
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())
}
fn __next__(mut slf: PyRefMut<Self>) -> PyResult<Option<i32>> {
fn __next__(mut slf: &mut PyClassShell<Self>) -> PyResult<Option<i32>> {
Ok(slf.iter.next())
}
}
@ -252,7 +250,7 @@ fn setitem() {
let gil = Python::acquire_gil();
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");
assert_eq!(c.key, 1);
assert_eq!(c.val, 2);
@ -277,7 +275,7 @@ fn delitem() {
let gil = Python::acquire_gil();
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]");
assert_eq!(c.key, 1);
py_expect_exception!(py, c, "c[1] = 2", NotImplementedError);
@ -306,7 +304,7 @@ fn setdelitem() {
let gil = Python::acquire_gil();
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");
assert_eq!(c.val, Some(2));
py_run!(py, c, "del c[1]");
@ -385,7 +383,7 @@ fn context_manager() {
let gil = Python::acquire_gil();
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");
assert!(c.exit_called);
@ -457,7 +455,7 @@ struct DunderDictSupport {}
fn dunder_dict_support() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyRef::new(py, DunderDictSupport {}).unwrap();
let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -472,7 +470,7 @@ fn dunder_dict_support() {
fn access_dunder_dict() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyRef::new(py, DunderDictSupport {}).unwrap();
let inst = PyClassShell::new_ref(py, DunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -490,7 +488,7 @@ struct WeakRefDunderDictSupport {}
fn weakref_dunder_dict_support() {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = PyRef::new(py, WeakRefDunderDictSupport {}).unwrap();
let inst = PyClassShell::new_ref(py, WeakRefDunderDictSupport {}).unwrap();
py_run!(
py,
inst,
@ -515,7 +513,7 @@ impl PyObjectProtocol for ClassWithGetAttr {
fn getattr_doesnt_override_member() {
let gil = Python::acquire_gil();
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.a == 8");
}

View file

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

View file

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

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

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

View file

@ -1,7 +1,7 @@
use pyo3::prelude::*;
use pyo3::py_run;
use pyo3::types::{IntoPyDict, PyDict, PyList, PySet, PyString, PyTuple, PyType};
use pyo3::PyRawObject;
use pyo3::PyClassShell;
mod common;
@ -23,7 +23,7 @@ fn instance_method() {
let gil = Python::acquire_gil();
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);
let d = [("obj", obj)].into_py_dict(py);
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 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);
let d = [("obj", obj)].into_py_dict(py);
py.run("assert obj.method(3) == 21", None, Some(d)).unwrap();
@ -63,8 +63,8 @@ struct ClassMethod {}
#[pymethods]
impl ClassMethod {
#[new]
fn new(obj: &PyRawObject) {
obj.init(ClassMethod {})
fn new() -> Self {
ClassMethod {}
}
#[classmethod]
@ -137,8 +137,8 @@ struct StaticMethod {}
#[pymethods]
impl StaticMethod {
#[new]
fn new(obj: &PyRawObject) {
obj.init(StaticMethod {})
fn new() -> Self {
StaticMethod {}
}
#[staticmethod]
@ -395,7 +395,7 @@ impl MethodWithLifeTime {
fn method_with_lifetime() {
let gil = Python::acquire_gil();
let py = gil.python();
let obj = PyRef::new(py, MethodWithLifeTime {}).unwrap();
let obj = PyClassShell::new_ref(py, MethodWithLifeTime {}).unwrap();
py_run!(
py,
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::prelude::*;
use pyo3::types::{PyBytes, PyString};
use pyo3::PyIterProtocol;
use pyo3::{AsPyRef, PyClassShell, PyIterProtocol};
use std::collections::HashMap;
mod common;
@ -10,20 +10,23 @@ mod common;
/// Assumes it's a file reader or so.
/// Inspired by https://github.com/jothan/cordoba, thanks.
#[pyclass]
#[derive(Clone)]
#[derive(Clone, Debug)]
struct Reader {
inner: HashMap<u8, String>,
}
#[pymethods]
impl Reader {
fn clone_ref(slf: PyRef<Self>) -> PyRef<Self> {
fn clone_ref(slf: &PyClassShell<Self>) -> &PyClassShell<Self> {
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
}
fn get_iter(slf: PyRef<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
fn get_iter(slf: &PyClassShell<Self>, keys: Py<PyBytes>) -> PyResult<Iter> {
Ok(Iter {
reader: slf.into(),
keys,
@ -31,7 +34,7 @@ impl Reader {
})
}
fn get_iter_and_reset(
mut slf: PyRefMut<Self>,
slf: &mut PyClassShell<Self>,
keys: Py<PyBytes>,
py: Python,
) -> PyResult<Iter> {
@ -54,13 +57,15 @@ struct Iter {
#[pyproto]
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() };
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() };
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) => {
let res = slf
.reader
@ -84,7 +89,7 @@ fn reader() -> Reader {
}
#[test]
fn test_nested_iter() {
fn test_nested_iter1() {
let gil = Python::acquire_gil();
let py = gil.python();
let reader: PyObject = reader().into_py(py);
@ -108,7 +113,7 @@ fn test_clone_ref() {
fn test_nested_iter_reset() {
let gil = Python::acquire_gil();
let py = gil.python();
let reader = PyRef::new(py, reader()).unwrap();
let reader = PyClassShell::new_ref(py, reader()).unwrap();
py_assert!(
py,
reader,

View file

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

View file

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

View file

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