Skip to content

Commit a663907

Browse files
committed
Introduce PyInternalCaster
1 parent 4d7dfaf commit a663907

20 files changed

+165
-167
lines changed

pyo3-derive-backend/src/method.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ impl<'a> FnSpec<'a> {
6565
ref pat, ref ty, ..
6666
}) => {
6767
// skip first argument (cls)
68-
if (fn_type == FnType::FnClass || fn_type == FnType::FnNew) && !has_self {
68+
if fn_type == FnType::FnClass && !has_self {
6969
has_self = true;
7070
continue;
7171
}

src/class/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ macro_rules! py_unary_pyref_func {
3535
where
3636
T: for<'p> $trait<'p>,
3737
{
38-
use $crate::{pyclass::PyClassShell, FromPyPointer};
38+
use $crate::pyclass::PyClassShell;
3939
let py = $crate::Python::assume_gil_acquired();
4040
let _pool = $crate::GILPool::new(py);
41-
let slf: &mut PyClassShell<T> = FromPyPointer::from_borrowed_ptr_or_panic(py, slf);
41+
let slf: &mut PyClassShell<T> = &mut *(slf as *mut PyClassShell<T>);
4242
let res = $class::$f(slf).into();
4343
$crate::callback::cb_convert($conv, py, res)
4444
}

src/conversion.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//! Conversions between various states of rust and python types and their wrappers.
44
use crate::err::{self, PyDowncastError, PyResult};
55
use crate::object::PyObject;
6-
use crate::type_object::PyTypeInfo;
6+
use crate::type_object::{PyConcreteObject, PyTypeInfo};
77
use crate::types::PyAny;
88
use crate::types::PyTuple;
99
use crate::{ffi, gil, Py, Python};
@@ -393,15 +393,13 @@ where
393393
#[inline]
394394
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v T {
395395
let value = value.into();
396-
let ptr = value as *const _ as *const u8 as *const T;
397-
&*ptr
396+
T::ConcreteLayout::internal_ref_cast(value)
398397
}
399398

400399
#[inline]
401400
unsafe fn try_from_mut_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v mut T {
402401
let value = value.into();
403-
let ptr = value as *const _ as *mut u8 as *mut T;
404-
&mut *ptr
402+
T::ConcreteLayout::internal_mut_cast(value)
405403
}
406404
}
407405

@@ -453,10 +451,11 @@ where
453451
T: PyTypeInfo,
454452
{
455453
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
456-
NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_owned(py, p)))
454+
NonNull::new(ptr).map(|p| T::ConcreteLayout::internal_ref_cast(gil::register_owned(py, p)))
457455
}
458456
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
459-
NonNull::new(ptr).map(|p| py.unchecked_downcast(gil::register_borrowed(py, p)))
457+
NonNull::new(ptr)
458+
.map(|p| T::ConcreteLayout::internal_ref_cast(gil::register_borrowed(py, p)))
460459
}
461460
}
462461

@@ -465,10 +464,11 @@ where
465464
T: PyTypeInfo,
466465
{
467466
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
468-
NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_owned(py, p)))
467+
NonNull::new(ptr).map(|p| T::ConcreteLayout::internal_mut_cast(gil::register_owned(py, p)))
469468
}
470469
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
471-
NonNull::new(ptr).map(|p| py.unchecked_mut_downcast(gil::register_borrowed(py, p)))
470+
NonNull::new(ptr)
471+
.map(|p| T::ConcreteLayout::internal_mut_cast(gil::register_borrowed(py, p)))
472472
}
473473
}
474474

src/instance.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
// Copyright (c) 2017-present PyO3 Project and Contributors
22
use crate::err::{PyErr, PyResult};
33
use crate::gil;
4-
use crate::instance;
54
use crate::object::PyObject;
65
use crate::objectprotocol::ObjectProtocol;
76
use crate::pyclass::{PyClass, PyClassShell};
8-
use crate::type_object::PyTypeInfo;
7+
use crate::type_object::{PyConcreteObject, PyTypeInfo};
98
use crate::types::PyAny;
109
use crate::{ffi, IntoPy};
1110
use crate::{AsPyPointer, FromPyObject, IntoPyPointer, Python, ToPyObject};
@@ -36,11 +35,6 @@ unsafe impl<T> Sync for Py<T> {}
3635

3736
impl<T> Py<T> {
3837
/// Create new instance of T and move it under python management
39-
///
40-
/// **NOTE**
41-
/// This method's `where` bound is actually the same as `PyClass`.
42-
/// However, since Rust still doesn't have higher order generics, we cannot represent
43-
/// this bound by `PyClass`.
4438
pub fn new(py: Python, value: T) -> PyResult<Py<T>>
4539
where
4640
T: PyClass,
@@ -128,7 +122,8 @@ pub trait AsPyRef<T: PyTypeInfo>: Sized {
128122

129123
impl<T: PyTypeInfo> AsPyRef<T> for Py<T> {
130124
fn as_ref(&self, _py: Python) -> &T {
131-
unsafe { &*(self as *const instance::Py<T> as *const T) }
125+
let any = self as *const Py<T> as *const PyAny;
126+
unsafe { T::ConcreteLayout::internal_ref_cast(&*any) }
132127
}
133128
}
134129

@@ -143,8 +138,8 @@ impl<T> IntoPy<PyObject> for Py<T> {
143138
/// Converts `Py` instance -> PyObject.
144139
/// Consumes `self` without calling `Py_DECREF()`
145140
#[inline]
146-
fn into_py(self, py: Python) -> PyObject {
147-
unsafe { PyObject::from_owned_ptr(py, self.into_ptr()) }
141+
fn into_py(self, _py: Python) -> PyObject {
142+
unsafe { PyObject::from_not_null(self.into_non_null()) }
148143
}
149144
}
150145

@@ -161,9 +156,25 @@ impl<T> IntoPyPointer for Py<T> {
161156
#[inline]
162157
#[must_use]
163158
fn into_ptr(self) -> *mut ffi::PyObject {
164-
let ptr = self.0.as_ptr();
165-
std::mem::forget(self);
166-
ptr
159+
self.into_non_null().as_ptr()
160+
}
161+
}
162+
163+
impl<'a, T> std::convert::From<&PyClassShell<T>> for Py<T>
164+
where
165+
T: PyClass,
166+
{
167+
fn from(shell: &PyClassShell<T>) -> Self {
168+
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
169+
}
170+
}
171+
172+
impl<'a, T> std::convert::From<&mut PyClassShell<T>> for Py<T>
173+
where
174+
T: PyClass,
175+
{
176+
fn from(shell: &mut PyClassShell<T>) -> Self {
177+
unsafe { Py::from_borrowed_ptr(shell.as_ptr()) }
167178
}
168179
}
169180

src/pyclass.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
33
use crate::conversion::{AsPyPointer, FromPyPointer, ToPyObject};
44
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
55
use crate::type_object::{type_flags, PyConcreteObject, PyTypeObject};
6+
use crate::types::PyAny;
67
use crate::{class, ffi, gil, PyErr, PyObject, PyResult, PyTypeInfo, Python};
78
use std::ffi::CString;
89
use std::mem::ManuallyDrop;
@@ -112,7 +113,15 @@ impl<T: PyClass> PyClassShell<T> {
112113
}
113114
}
114115

115-
impl<T: PyClass> PyConcreteObject for PyClassShell<T> {
116+
impl<T: PyClass> PyConcreteObject<T> for PyClassShell<T> {
117+
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
118+
let shell = obj.as_ptr() as *const PyClassShell<T>;
119+
&*(*shell).pyclass
120+
}
121+
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
122+
let shell = obj.as_ptr() as *const PyClassShell<T> as *mut PyClassShell<T>;
123+
&mut *(*shell).pyclass
124+
}
116125
unsafe fn py_drop(&mut self, py: Python) {
117126
ManuallyDrop::drop(&mut self.pyclass);
118127
self.dict.clear_dict(py);
@@ -121,6 +130,12 @@ impl<T: PyClass> PyConcreteObject for PyClassShell<T> {
121130
}
122131
}
123132

133+
impl<T: PyClass> AsPyPointer for PyClassShell<T> {
134+
fn as_ptr(&self) -> *mut ffi::PyObject {
135+
(self as *const _) as *mut _
136+
}
137+
}
138+
124139
impl<T: PyClass> std::ops::Deref for PyClassShell<T> {
125140
type Target = T;
126141
fn deref(&self) -> &T {
@@ -134,7 +149,13 @@ impl<T: PyClass> std::ops::DerefMut for PyClassShell<T> {
134149
}
135150
}
136151

137-
impl<T: PyClass> ToPyObject for PyClassShell<T> {
152+
impl<T: PyClass> ToPyObject for &PyClassShell<T> {
153+
fn to_object(&self, py: Python<'_>) -> PyObject {
154+
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
155+
}
156+
}
157+
158+
impl<T: PyClass> ToPyObject for &mut PyClassShell<T> {
138159
fn to_object(&self, py: Python<'_>) -> PyObject {
139160
unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
140161
}
@@ -145,10 +166,11 @@ where
145166
T: PyClass,
146167
{
147168
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
148-
NonNull::new(ptr).map(|p| &**(gil::register_owned(py, p) as *const _ as *const Self))
169+
NonNull::new(ptr).map(|p| &*(gil::register_owned(py, p).as_ptr() as *const PyClassShell<T>))
149170
}
150171
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
151-
NonNull::new(ptr).map(|p| &**(gil::register_borrowed(py, p) as *const _ as *const Self))
172+
NonNull::new(ptr)
173+
.map(|p| &*(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell<T>))
152174
}
153175
}
154176

@@ -157,10 +179,14 @@ where
157179
T: PyClass,
158180
{
159181
unsafe fn from_owned_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
160-
NonNull::new(ptr).map(|p| &mut **(gil::register_owned(py, p) as *const _ as *mut Self))
182+
NonNull::new(ptr).map(|p| {
183+
&mut *(gil::register_owned(py, p).as_ptr() as *const PyClassShell<T> as *mut _)
184+
})
161185
}
162186
unsafe fn from_borrowed_ptr_or_opt(py: Python<'p>, ptr: *mut ffi::PyObject) -> Option<Self> {
163-
NonNull::new(ptr).map(|p| &mut **(gil::register_borrowed(py, p) as *const _ as *mut Self))
187+
NonNull::new(ptr).map(|p| {
188+
&mut *(gil::register_borrowed(py, p).as_ptr() as *const PyClassShell<T> as *mut _)
189+
})
164190
}
165191
}
166192

src/python.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::ffi;
77
use crate::gil::{self, GILGuard};
88
use crate::instance::AsPyRef;
99
use crate::object::PyObject;
10-
use crate::type_object::{PyTypeInfo, PyTypeObject};
10+
use crate::type_object::{PyConcreteObject, PyTypeInfo, PyTypeObject};
1111
use crate::types::{PyAny, PyDict, PyModule, PyType};
1212
use crate::AsPyPointer;
1313
use crate::{FromPyPointer, IntoPyPointer, PyTryFrom};
@@ -272,16 +272,6 @@ impl<'p> Python<'p> {
272272
}
273273

274274
impl<'p> Python<'p> {
275-
// TODO(kngwyu): Now offset dies, so what should this functions do
276-
pub(crate) unsafe fn unchecked_downcast<T: PyTypeInfo>(self, ob: &PyAny) -> &'p T {
277-
&*(ob as *const _ as *const T)
278-
}
279-
280-
#[allow(clippy::cast_ref_to_mut)] // FIXME
281-
pub(crate) unsafe fn unchecked_mut_downcast<T: PyTypeInfo>(self, ob: &PyAny) -> &'p mut T {
282-
&mut *(ob as *const _ as *mut T)
283-
}
284-
285275
/// Register object in release pool, and try to downcast to specific type.
286276
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'p T, PyDowncastError>
287277
where
@@ -297,7 +287,7 @@ impl<'p> Python<'p> {
297287
T: PyTypeInfo,
298288
{
299289
let p = gil::register_owned(self, obj.into_nonnull());
300-
self.unchecked_downcast(p)
290+
T::ConcreteLayout::internal_ref_cast(p)
301291
}
302292

303293
/// Register `ffi::PyObject` pointer in release pool

src/type_object.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@
44
55
use crate::ffi;
66
use crate::instance::Py;
7+
use crate::instance::PyNativeType;
78
use crate::types::PyAny;
89
use crate::types::PyType;
910
use crate::AsPyPointer;
1011
use crate::Python;
1112
use std::ptr::NonNull;
1213

1314
/// TODO: write document
14-
pub trait PyConcreteObject: Sized {
15-
unsafe fn py_drop(&mut self, _py: Python) {}
16-
}
17-
18-
impl<T: PyConcreteObject> AsPyPointer for T {
19-
fn as_ptr(&self) -> *mut ffi::PyObject {
20-
(self as *const _) as _
15+
pub trait PyConcreteObject<T>: Sized {
16+
unsafe fn internal_ref_cast(obj: &PyAny) -> &T {
17+
&*(obj as *const _ as *const T)
2118
}
19+
unsafe fn internal_mut_cast(obj: &PyAny) -> &mut T {
20+
&mut *(obj as *const _ as *const T as *mut T)
21+
}
22+
unsafe fn py_drop(&mut self, _py: Python) {}
2223
}
2324

24-
impl PyConcreteObject for ffi::PyObject {}
25+
impl<T: PyNativeType> PyConcreteObject<T> for ffi::PyObject {}
2526

2627
/// Our custom type flags
2728
pub mod type_flags {
@@ -39,7 +40,7 @@ pub mod type_flags {
3940
}
4041

4142
/// Python type information.
42-
pub trait PyTypeInfo {
43+
pub trait PyTypeInfo: Sized {
4344
/// Type of objects to store in PyObject struct
4445
type Type;
4546

@@ -59,7 +60,7 @@ pub trait PyTypeInfo {
5960
type BaseType: PyTypeInfo;
6061

6162
/// Layout
62-
type ConcreteLayout: PyConcreteObject;
63+
type ConcreteLayout: PyConcreteObject<Self>;
6364

6465
/// PyTypeObject instance for this type, which might still need to
6566
/// be initialized

tests/test_class_basics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use pyo3::prelude::*;
22
use pyo3::py_run;
3-
use pyo3::type_object::initialize_type;
3+
use pyo3::pyclass::initialize_type;
44

55
mod common;
66

tests/test_class_new.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,13 @@
11
use pyo3::prelude::*;
2-
use pyo3::PyRawObject;
32

43
#[pyclass]
54
struct EmptyClassWithNew {}
65

76
#[pymethods]
87
impl EmptyClassWithNew {
98
#[new]
10-
fn new(obj: &PyRawObject) {
11-
obj.init(EmptyClassWithNew {});
9+
fn new() -> EmptyClassWithNew {
10+
EmptyClassWithNew {}
1211
}
1312
}
1413

@@ -25,15 +24,16 @@ fn empty_class_with_new() {
2524
}
2625

2726
#[pyclass]
27+
#[derive(Debug)]
2828
struct NewWithOneArg {
2929
_data: i32,
3030
}
3131

3232
#[pymethods]
3333
impl NewWithOneArg {
3434
#[new]
35-
fn new(obj: &PyRawObject, arg: i32) {
36-
obj.init(NewWithOneArg { _data: arg })
35+
fn new(arg: i32) -> NewWithOneArg {
36+
NewWithOneArg { _data: arg }
3737
}
3838
}
3939

@@ -56,11 +56,11 @@ struct NewWithTwoArgs {
5656
#[pymethods]
5757
impl NewWithTwoArgs {
5858
#[new]
59-
fn new(obj: &PyRawObject, arg1: i32, arg2: i32) {
60-
obj.init(NewWithTwoArgs {
59+
fn new(arg1: i32, arg2: i32) -> Self {
60+
NewWithTwoArgs {
6161
_data1: arg1,
6262
_data2: arg2,
63-
})
63+
}
6464
}
6565
}
6666

tests/test_datetime.rs

100644100755
File mode changed.

0 commit comments

Comments
 (0)