Skip to content

Commit e28ea8e

Browse files
committed
implement PyTypeMethods
1 parent 066e334 commit e28ea8e

File tree

3 files changed

+100
-30
lines changed

3 files changed

+100
-30
lines changed

src/prelude.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,4 @@ pub use crate::types::mapping::PyMappingMethods;
3737
pub use crate::types::sequence::PySequenceMethods;
3838
pub use crate::types::set::PySetMethods;
3939
pub use crate::types::string::PyStringMethods;
40+
pub use crate::types::typeobject::PyTypeMethods;

src/types/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,4 @@ mod slice;
306306
pub(crate) mod string;
307307
mod traceback;
308308
mod tuple;
309-
mod typeobject;
309+
pub(crate) mod typeobject;

src/types/typeobject.rs

Lines changed: 98 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::err::{self, PyResult};
2-
use crate::{ffi, PyAny, PyTypeInfo, Python};
2+
use crate::ffi_ptr_ext::FfiPtrExt;
3+
use crate::instance::Borrowed;
4+
use crate::types::any::PyAnyMethods;
5+
use crate::{ffi, Bound, PyAny, PyNativeType, PyTypeInfo, Python};
36
use std::borrow::Cow;
47
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
58
use std::ffi::CStr;
@@ -20,7 +23,7 @@ impl PyType {
2023
/// Retrieves the underlying FFI pointer associated with this Python object.
2124
#[inline]
2225
pub fn as_type_ptr(&self) -> *mut ffi::PyTypeObject {
23-
self.as_ptr() as *mut ffi::PyTypeObject
26+
self.as_borrowed().as_type_ptr()
2427
}
2528

2629
/// Retrieves the `PyType` instance for the given FFI pointer.
@@ -35,14 +38,81 @@ impl PyType {
3538

3639
/// Gets the [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the `PyType`.
3740
pub fn qualname(&self) -> PyResult<String> {
41+
self.as_borrowed().qualname()
42+
}
43+
44+
/// Gets the full name, which includes the module, of the `PyType`.
45+
pub fn name(&self) -> PyResult<Cow<'_, str>> {
46+
self.as_borrowed().name()
47+
}
48+
49+
/// Checks whether `self` is a subclass of `other`.
50+
///
51+
/// Equivalent to the Python expression `issubclass(self, other)`.
52+
pub fn is_subclass(&self, other: &PyAny) -> PyResult<bool> {
53+
self.as_borrowed().is_subclass(&other.as_borrowed())
54+
}
55+
56+
/// Checks whether `self` is a subclass of type `T`.
57+
///
58+
/// Equivalent to the Python expression `issubclass(self, T)`, if the type
59+
/// `T` is known at compile time.
60+
pub fn is_subclass_of<T>(&self) -> PyResult<bool>
61+
where
62+
T: PyTypeInfo,
63+
{
64+
self.as_borrowed().is_subclass_of::<T>()
65+
}
66+
}
67+
68+
/// Implementation of functionality for [`PyType`].
69+
///
70+
/// These methods are defined for the `Bound<'py, PyType>` smart pointer, so to use method call
71+
/// syntax these methods are separated into a trait, because stable Rust does not yet support
72+
/// `arbitrary_self_types`.
73+
#[doc(alias = "PyType")]
74+
pub trait PyTypeMethods<'py> {
75+
/// Retrieves the underlying FFI pointer associated with this Python object.
76+
fn as_type_ptr(&self) -> *mut ffi::PyTypeObject;
77+
78+
/// Gets the full name, which includes the module, of the `PyType`.
79+
fn name(&self) -> PyResult<Cow<'_, str>>;
80+
81+
/// Gets the [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the `PyType`.
82+
fn qualname(&self) -> PyResult<String>;
83+
84+
/// Checks whether `self` is a subclass of `other`.
85+
///
86+
/// Equivalent to the Python expression `issubclass(self, other)`.
87+
fn is_subclass(&self, other: &Bound<'_, PyAny>) -> PyResult<bool>;
88+
89+
/// Checks whether `self` is a subclass of type `T`.
90+
///
91+
/// Equivalent to the Python expression `issubclass(self, T)`, if the type
92+
/// `T` is known at compile time.
93+
fn is_subclass_of<T>(&self) -> PyResult<bool>
94+
where
95+
T: PyTypeInfo;
96+
}
97+
98+
impl<'py> PyTypeMethods<'py> for Bound<'py, PyType> {
99+
/// Retrieves the underlying FFI pointer associated with this Python object.
100+
#[inline]
101+
fn as_type_ptr(&self) -> *mut ffi::PyTypeObject {
102+
self.as_ptr() as *mut ffi::PyTypeObject
103+
}
104+
105+
/// Gets the name of the `PyType`.
106+
fn name(&self) -> PyResult<Cow<'_, str>> {
107+
Borrowed::from(self).name()
108+
}
109+
110+
fn qualname(&self) -> PyResult<String> {
38111
#[cfg(any(Py_LIMITED_API, PyPy, not(Py_3_11)))]
39112
let name = self.getattr(intern!(self.py(), "__qualname__"))?.extract();
40113

41114
#[cfg(not(any(Py_LIMITED_API, PyPy, not(Py_3_11))))]
42115
let name = {
43-
use crate::ffi_ptr_ext::FfiPtrExt;
44-
use crate::types::any::PyAnyMethods;
45-
46116
let obj = unsafe {
47117
ffi::PyType_GetQualName(self.as_type_ptr()).assume_owned_or_err(self.py())?
48118
};
@@ -53,8 +123,29 @@ impl PyType {
53123
name
54124
}
55125

56-
/// Gets the full name, which includes the module, of the `PyType`.
57-
pub fn name(&self) -> PyResult<Cow<'_, str>> {
126+
/// Checks whether `self` is a subclass of `other`.
127+
///
128+
/// Equivalent to the Python expression `issubclass(self, other)`.
129+
fn is_subclass(&self, other: &Bound<'_, PyAny>) -> PyResult<bool> {
130+
let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), other.as_ptr()) };
131+
err::error_on_minusone(self.py(), result)?;
132+
Ok(result == 1)
133+
}
134+
135+
/// Checks whether `self` is a subclass of type `T`.
136+
///
137+
/// Equivalent to the Python expression `issubclass(self, T)`, if the type
138+
/// `T` is known at compile time.
139+
fn is_subclass_of<T>(&self) -> PyResult<bool>
140+
where
141+
T: PyTypeInfo,
142+
{
143+
self.is_subclass(&T::type_object(self.py()).as_borrowed())
144+
}
145+
}
146+
147+
impl<'a> Borrowed<'a, '_, PyType> {
148+
fn name(self) -> PyResult<Cow<'a, str>> {
58149
#[cfg(not(any(Py_LIMITED_API, PyPy)))]
59150
{
60151
let ptr = self.as_type_ptr();
@@ -78,34 +169,12 @@ impl PyType {
78169

79170
#[cfg(Py_3_11)]
80171
let name = {
81-
use crate::ffi_ptr_ext::FfiPtrExt;
82-
83172
unsafe { ffi::PyType_GetName(self.as_type_ptr()).assume_owned_or_err(self.py())? }
84173
};
85174

86175
Ok(Cow::Owned(format!("{}.{}", module, name)))
87176
}
88177
}
89-
90-
/// Checks whether `self` is a subclass of `other`.
91-
///
92-
/// Equivalent to the Python expression `issubclass(self, other)`.
93-
pub fn is_subclass(&self, other: &PyAny) -> PyResult<bool> {
94-
let result = unsafe { ffi::PyObject_IsSubclass(self.as_ptr(), other.as_ptr()) };
95-
err::error_on_minusone(self.py(), result)?;
96-
Ok(result == 1)
97-
}
98-
99-
/// Checks whether `self` is a subclass of type `T`.
100-
///
101-
/// Equivalent to the Python expression `issubclass(self, T)`, if the type
102-
/// `T` is known at compile time.
103-
pub fn is_subclass_of<T>(&self) -> PyResult<bool>
104-
where
105-
T: PyTypeInfo,
106-
{
107-
self.is_subclass(T::type_object(self.py()))
108-
}
109178
}
110179

111180
#[cfg(test)]

0 commit comments

Comments
 (0)