Skip to content

Commit 7ecd127

Browse files
committed
replace PyTryFrom by splitting PyTypeInfo
1 parent 0f34fcd commit 7ecd127

19 files changed

+213
-214
lines changed

guide/src/class.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1108,8 +1108,10 @@ struct MyClass {
11081108
# #[allow(dead_code)]
11091109
num: i32,
11101110
}
1111-
unsafe impl pyo3::type_object::PyTypeInfo for MyClass {
1111+
unsafe impl pyo3::type_object::HasPyGilRef for MyClass {
11121112
type AsRefTarget = pyo3::PyCell<Self>;
1113+
}
1114+
unsafe impl pyo3::type_object::PyTypeInfo for MyClass {
11131115
const NAME: &'static str = "MyClass";
11141116
const MODULE: ::std::option::Option<&'static str> = ::std::option::Option::None;
11151117
#[inline]

newsfragments/3600.changed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Split some `PyTypeInfo` functionality into new traits `HasPyGilRef` and `PyTypeCheck`.

pyo3-macros-backend/src/pyclass.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -753,9 +753,11 @@ fn impl_pytypeinfo(
753753
};
754754

755755
quote! {
756-
unsafe impl _pyo3::type_object::PyTypeInfo for #cls {
756+
unsafe impl _pyo3::type_object::HasPyGilRef for #cls {
757757
type AsRefTarget = _pyo3::PyCell<Self>;
758+
}
758759

760+
unsafe impl _pyo3::type_object::PyTypeInfo for #cls {
759761
const NAME: &'static str = #cls_name;
760762
const MODULE: ::std::option::Option<&'static str> = #module;
761763

src/conversion.rs

Lines changed: 52 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ where
304304
T: PyClass,
305305
{
306306
fn extract(obj: &'a PyAny) -> PyResult<Self> {
307-
PyTryFrom::try_from(obj).map_err(Into::into)
307+
obj.downcast().map_err(Into::into)
308308
}
309309
}
310310

@@ -313,7 +313,7 @@ where
313313
T: PyClass + Clone,
314314
{
315315
fn extract(obj: &'a PyAny) -> PyResult<Self> {
316-
let cell: &PyCell<Self> = PyTryFrom::try_from(obj)?;
316+
let cell: &PyCell<Self> = obj.downcast()?;
317317
Ok(unsafe { cell.try_borrow_unguarded()?.clone() })
318318
}
319319
}
@@ -323,7 +323,7 @@ where
323323
T: PyClass,
324324
{
325325
fn extract(obj: &'a PyAny) -> PyResult<Self> {
326-
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
326+
let cell: &PyCell<T> = obj.downcast()?;
327327
cell.try_borrow().map_err(Into::into)
328328
}
329329
}
@@ -333,7 +333,7 @@ where
333333
T: PyClass<Frozen = False>,
334334
{
335335
fn extract(obj: &'a PyAny) -> PyResult<Self> {
336-
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
336+
let cell: &PyCell<T> = obj.downcast()?;
337337
cell.try_borrow_mut().map_err(Into::into)
338338
}
339339
}
@@ -381,78 +381,61 @@ pub trait PyTryInto<T>: Sized {
381381
fn try_into_exact(&self) -> Result<&T, PyDowncastError<'_>>;
382382
}
383383

384-
// TryFrom implies TryInto
385-
impl<U> PyTryInto<U> for PyAny
386-
where
387-
U: for<'v> PyTryFrom<'v>,
388-
{
389-
fn try_into(&self) -> Result<&U, PyDowncastError<'_>> {
390-
<U as PyTryFrom<'_>>::try_from(self)
391-
}
392-
fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> {
393-
U::try_from_exact(self)
394-
}
395-
}
384+
mod implementations {
385+
use super::*;
396386

397-
impl<'v, T> PyTryFrom<'v> for T
398-
where
399-
T: PyTypeInfo + PyNativeType,
400-
{
401-
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
402-
let value = value.into();
403-
unsafe {
404-
if T::is_type_of(value) {
405-
Ok(Self::try_from_unchecked(value))
406-
} else {
407-
Err(PyDowncastError::new(value, T::NAME))
408-
}
387+
// TryFrom implies TryInto
388+
impl<U> PyTryInto<U> for PyAny
389+
where
390+
U: for<'v> PyTryFrom<'v>,
391+
{
392+
fn try_into(&self) -> Result<&U, PyDowncastError<'_>> {
393+
<U as PyTryFrom<'_>>::try_from(self)
394+
}
395+
fn try_into_exact(&self) -> Result<&U, PyDowncastError<'_>> {
396+
U::try_from_exact(self)
409397
}
410398
}
411399

412-
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
413-
let value = value.into();
414-
unsafe {
415-
if T::is_exact_type_of(value) {
416-
Ok(Self::try_from_unchecked(value))
417-
} else {
418-
Err(PyDowncastError::new(value, T::NAME))
419-
}
400+
impl<'v, T> PyTryFrom<'v> for T
401+
where
402+
T: PyTypeInfo<AsRefTarget = Self> + PyNativeType,
403+
{
404+
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
405+
value.into().downcast()
420406
}
421-
}
422407

423-
#[inline]
424-
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
425-
Self::unchecked_downcast(value.into())
426-
}
427-
}
408+
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
409+
value.into().downcast_exact()
410+
}
428411

429-
impl<'v, T> PyTryFrom<'v> for PyCell<T>
430-
where
431-
T: 'v + PyClass,
432-
{
433-
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
434-
let value = value.into();
435-
unsafe {
436-
if T::is_type_of(value) {
437-
Ok(Self::try_from_unchecked(value))
438-
} else {
439-
Err(PyDowncastError::new(value, T::NAME))
440-
}
412+
#[inline]
413+
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
414+
value.into().downcast_unchecked()
441415
}
442416
}
443-
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
444-
let value = value.into();
445-
unsafe {
446-
if T::is_exact_type_of(value) {
447-
Ok(Self::try_from_unchecked(value))
448-
} else {
449-
Err(PyDowncastError::new(value, T::NAME))
417+
418+
impl<'v, T> PyTryFrom<'v> for PyCell<T>
419+
where
420+
T: 'v + PyClass,
421+
{
422+
fn try_from<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
423+
value.into().downcast()
424+
}
425+
fn try_from_exact<V: Into<&'v PyAny>>(value: V) -> Result<&'v Self, PyDowncastError<'v>> {
426+
let value = value.into();
427+
unsafe {
428+
if T::is_exact_type_of(value) {
429+
Ok(Self::try_from_unchecked(value))
430+
} else {
431+
Err(PyDowncastError::new(value, T::NAME))
432+
}
450433
}
451434
}
452-
}
453-
#[inline]
454-
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
455-
Self::unchecked_downcast(value.into())
435+
#[inline]
436+
unsafe fn try_from_unchecked<V: Into<&'v PyAny>>(value: V) -> &'v Self {
437+
value.into().downcast_unchecked()
438+
}
456439
}
457440
}
458441

@@ -572,10 +555,11 @@ mod test_no_clone {}
572555

573556
#[cfg(test)]
574557
mod tests {
575-
use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
576-
use crate::{PyObject, Python, ToPyObject};
558+
use crate::PyObject;
577559

578-
use super::PyTryFrom;
560+
use super::super::PyTryFrom;
561+
use crate::types::{IntoPyDict, PyAny, PyDict, PyList};
562+
use crate::{Python, ToPyObject};
579563

580564
#[test]
581565
fn test_try_from() {

src/instance.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
use crate::conversion::PyTryFrom;
21
use crate::err::{self, PyDowncastError, PyErr, PyResult};
3-
use crate::gil;
42
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
53
use crate::pyclass::boolean_struct::{False, True};
4+
use crate::type_object::HasPyGilRef;
65
use crate::types::any::PyAnyMethods;
76
use crate::types::{PyDict, PyString, PyTuple};
87
use crate::{
98
ffi, AsPyPointer, FromPyObject, IntoPy, PyAny, PyClass, PyClassInitializer, PyRef, PyRefMut,
109
PyTypeInfo, Python, ToPyObject,
1110
};
11+
use crate::{gil, PyTypeCheck};
1212
use std::marker::PhantomData;
1313
use std::mem::{self, ManuallyDrop};
1414
use std::ops::Deref;
@@ -185,7 +185,7 @@ impl<'py, T> Py2<'py, T> {
185185
#[doc(hidden)] // public and doc(hidden) to use in examples and tests for now
186186
pub fn as_gil_ref(&'py self) -> &'py T::AsRefTarget
187187
where
188-
T: PyTypeInfo,
188+
T: HasPyGilRef,
189189
{
190190
unsafe { self.py().from_borrowed_ptr(self.as_ptr()) }
191191
}
@@ -194,7 +194,7 @@ impl<'py, T> Py2<'py, T> {
194194
#[doc(hidden)] // public but hidden, to use for tests for now
195195
pub fn into_gil_ref(self) -> &'py T::AsRefTarget
196196
where
197-
T: PyTypeInfo,
197+
T: HasPyGilRef,
198198
{
199199
unsafe { self.py().from_owned_ptr(self.into_ptr()) }
200200
}
@@ -437,7 +437,7 @@ where
437437

438438
impl<T> Py<T>
439439
where
440-
T: PyTypeInfo,
440+
T: HasPyGilRef,
441441
{
442442
/// Borrows a GIL-bound reference to the contained `T`.
443443
///
@@ -1314,11 +1314,11 @@ impl PyObject {
13141314
/// # }
13151315
/// ```
13161316
#[inline]
1317-
pub fn downcast<'p, T>(&'p self, py: Python<'p>) -> Result<&T, PyDowncastError<'_>>
1317+
pub fn downcast<'py, T>(&'py self, py: Python<'py>) -> Result<&'py T, PyDowncastError<'py>>
13181318
where
1319-
T: PyTryFrom<'p>,
1319+
T: PyTypeCheck<AsRefTarget = T>,
13201320
{
1321-
<T as PyTryFrom<'_>>::try_from(self.as_ref(py))
1321+
self.as_ref(py).downcast()
13221322
}
13231323

13241324
/// Casts the PyObject to a concrete Python object type without checking validity.
@@ -1329,9 +1329,9 @@ impl PyObject {
13291329
#[inline]
13301330
pub unsafe fn downcast_unchecked<'p, T>(&'p self, py: Python<'p>) -> &T
13311331
where
1332-
T: PyTryFrom<'p>,
1332+
T: HasPyGilRef<AsRefTarget = T>,
13331333
{
1334-
<T as PyTryFrom<'_>>::try_from_unchecked(self.as_ref(py))
1334+
self.as_ref(py).downcast_unchecked()
13351335
}
13361336
}
13371337

src/lib.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,9 +294,8 @@
294294
//! [Features chapter of the guide]: https://pyo3.rs/latest/features.html#features-reference "Features Reference - PyO3 user guide"
295295
//! [`Ungil`]: crate::marker::Ungil
296296
pub use crate::class::*;
297-
pub use crate::conversion::{
298-
AsPyPointer, FromPyObject, FromPyPointer, IntoPy, PyTryFrom, PyTryInto, ToPyObject,
299-
};
297+
pub use crate::conversion::{AsPyPointer, FromPyObject, FromPyPointer, IntoPy, ToPyObject};
298+
pub use crate::conversion::{PyTryFrom, PyTryInto};
300299
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyResult};
301300
pub use crate::gil::GILPool;
302301
#[cfg(not(PyPy))]
@@ -306,7 +305,7 @@ pub use crate::marker::Python;
306305
pub use crate::pycell::{PyCell, PyRef, PyRefMut};
307306
pub use crate::pyclass::PyClass;
308307
pub use crate::pyclass_init::PyClassInitializer;
309-
pub use crate::type_object::PyTypeInfo;
308+
pub use crate::type_object::{PyTypeCheck, PyTypeInfo};
310309
pub use crate::types::PyAny;
311310
pub use crate::version::PythonVersionInfo;
312311

src/marker.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,12 @@
118118
use crate::err::{self, PyDowncastError, PyErr, PyResult};
119119
use crate::gil::{GILGuard, GILPool, SuspendGIL};
120120
use crate::impl_::not_send::NotSend;
121+
use crate::type_object::HasPyGilRef;
121122
use crate::types::{
122123
PyAny, PyDict, PyEllipsis, PyModule, PyNone, PyNotImplemented, PyString, PyType,
123124
};
124125
use crate::version::PythonVersionInfo;
125-
use crate::{ffi, FromPyPointer, IntoPy, Py, PyNativeType, PyObject, PyTryFrom, PyTypeInfo};
126+
use crate::{ffi, FromPyPointer, IntoPy, Py, PyObject, PyTypeCheck, PyTypeInfo};
126127
use std::ffi::{CStr, CString};
127128
use std::marker::PhantomData;
128129
use std::os::raw::c_int;
@@ -759,10 +760,9 @@ impl<'py> Python<'py> {
759760
/// Registers the object in the release pool, and tries to downcast to specific type.
760761
pub fn checked_cast_as<T>(self, obj: PyObject) -> Result<&'py T, PyDowncastError<'py>>
761762
where
762-
T: PyTryFrom<'py>,
763+
T: PyTypeCheck<AsRefTarget = T>,
763764
{
764-
let any: &PyAny = unsafe { self.from_owned_ptr(obj.into_ptr()) };
765-
<T as PyTryFrom>::try_from(any)
765+
obj.into_ref(self).downcast()
766766
}
767767

768768
/// Registers the object in the release pool, and does an unchecked downcast
@@ -773,10 +773,9 @@ impl<'py> Python<'py> {
773773
/// Callers must ensure that ensure that the cast is valid.
774774
pub unsafe fn cast_as<T>(self, obj: PyObject) -> &'py T
775775
where
776-
T: PyNativeType + PyTypeInfo,
776+
T: HasPyGilRef<AsRefTarget = T>,
777777
{
778-
let any: &PyAny = self.from_owned_ptr(obj.into_ptr());
779-
T::unchecked_downcast(any)
778+
obj.into_ref(self).downcast_unchecked()
780779
}
781780

782781
/// Registers the object pointer in the release pool,

src/prelude.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
//! use pyo3::prelude::*;
99
//! ```
1010
11-
pub use crate::conversion::{FromPyObject, IntoPy, PyTryFrom, PyTryInto, ToPyObject};
11+
pub use crate::conversion::{FromPyObject, IntoPy, ToPyObject};
12+
pub use crate::conversion::{PyTryFrom, PyTryInto};
1213
pub use crate::err::{PyErr, PyResult};
1314
pub use crate::instance::{Py, PyObject};
1415
pub use crate::marker::Python;

src/pycell.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ use crate::{
207207
type_object::get_tp_free,
208208
PyTypeInfo,
209209
};
210-
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
210+
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, PyTypeCheck, Python};
211211
use std::cell::UnsafeCell;
212212
use std::fmt;
213213
use std::mem::ManuallyDrop;
@@ -527,6 +527,17 @@ impl<T: PyClassImpl> PyCell<T> {
527527
unsafe impl<T: PyClassImpl> PyLayout<T> for PyCell<T> {}
528528
impl<T: PyClass> PySizedLayout<T> for PyCell<T> {}
529529

530+
impl<T> PyTypeCheck for PyCell<T>
531+
where
532+
T: PyClass,
533+
{
534+
const NAME: &'static str = <T as PyTypeCheck>::NAME;
535+
536+
fn type_check(object: &PyAny) -> bool {
537+
<T as PyTypeCheck>::type_check(object)
538+
}
539+
}
540+
530541
unsafe impl<T: PyClass> AsPyPointer for PyCell<T> {
531542
fn as_ptr(&self) -> *mut ffi::PyObject {
532543
(self as *const _) as *mut _

0 commit comments

Comments
 (0)