pyo3/impl_/
pyclass_init.rs
1use crate::ffi_ptr_ext::FfiPtrExt;
3use crate::internal::get_slot::TP_ALLOC;
4use crate::types::PyType;
5use crate::{ffi, Borrowed, PyErr, PyResult, Python};
6use crate::{ffi::PyTypeObject, sealed::Sealed, type_object::PyTypeInfo};
7use std::marker::PhantomData;
8use std::ptr;
9
10pub trait PyObjectInit<T>: Sized + Sealed {
15 unsafe fn into_new_object(
18 self,
19 py: Python<'_>,
20 subtype: *mut PyTypeObject,
21 ) -> PyResult<*mut ffi::PyObject>;
22
23 #[doc(hidden)]
24 fn can_be_subclassed(&self) -> bool;
25}
26
27pub struct PyNativeTypeInitializer<T: PyTypeInfo>(pub PhantomData<T>);
29
30impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> {
31 unsafe fn into_new_object(
32 self,
33 py: Python<'_>,
34 subtype: *mut PyTypeObject,
35 ) -> PyResult<*mut ffi::PyObject> {
36 unsafe fn inner(
37 py: Python<'_>,
38 type_object: *mut PyTypeObject,
39 subtype: *mut PyTypeObject,
40 ) -> PyResult<*mut ffi::PyObject> {
41 let is_base_object = ptr::eq(type_object, ptr::addr_of!(ffi::PyBaseObject_Type));
43 let subtype_borrowed: Borrowed<'_, '_, PyType> = unsafe {
44 subtype
45 .cast::<ffi::PyObject>()
46 .assume_borrowed_unchecked(py)
47 .downcast_unchecked()
48 };
49
50 if is_base_object {
51 let alloc = subtype_borrowed
52 .get_slot(TP_ALLOC)
53 .unwrap_or(ffi::PyType_GenericAlloc);
54
55 let obj = unsafe { alloc(subtype, 0) };
56 return if obj.is_null() {
57 Err(PyErr::fetch(py))
58 } else {
59 Ok(obj)
60 };
61 }
62
63 #[cfg(Py_LIMITED_API)]
64 unreachable!("subclassing native types is not possible with the `abi3` feature");
65
66 #[cfg(not(Py_LIMITED_API))]
67 {
68 match unsafe { (*type_object).tp_new } {
69 Some(newfunc) => {
71 let obj =
72 unsafe { newfunc(subtype, std::ptr::null_mut(), std::ptr::null_mut()) };
73 if obj.is_null() {
74 Err(PyErr::fetch(py))
75 } else {
76 Ok(obj)
77 }
78 }
79 None => Err(crate::exceptions::PyTypeError::new_err(
80 "base type without tp_new",
81 )),
82 }
83 }
84 }
85 let type_object = T::type_object_raw(py);
86 unsafe { inner(py, type_object, subtype) }
87 }
88
89 #[inline]
90 fn can_be_subclassed(&self) -> bool {
91 true
92 }
93}