|
1 | | -//! Contains initialization utilities for `#[pyclass]`. |
2 | | -use crate::exceptions::PyTypeError; |
3 | | -use crate::ffi_ptr_ext::FfiPtrExt; |
4 | | -use crate::impl_::pyclass::PyClassBaseType; |
5 | | -use crate::internal::get_slot::TP_NEW; |
6 | | -use crate::types::{PyTuple, PyType}; |
7 | | -use crate::{ffi, PyClass, PyClassInitializer, PyErr, PyResult, Python}; |
8 | | -use crate::{ffi::PyTypeObject, sealed::Sealed, type_object::PyTypeInfo}; |
9 | | -use core::marker::PhantomData; |
10 | | - |
11 | | -/// Initializer for Python types. |
12 | | -/// |
13 | | -/// This trait is intended to use internally for distinguishing `#[pyclass]` and |
14 | | -/// Python native types. |
15 | | -pub trait PyObjectInit<T>: Sized + Sealed { |
16 | | - /// # Safety |
17 | | - /// - `subtype` must be a valid pointer to a type object of T or a subclass. |
18 | | - unsafe fn into_new_object( |
19 | | - self, |
20 | | - py: Python<'_>, |
21 | | - subtype: *mut PyTypeObject, |
22 | | - ) -> PyResult<*mut ffi::PyObject>; |
23 | | -} |
24 | | - |
25 | | -/// Initializer for Python native types, like `PyDict`. |
26 | | -pub struct PyNativeTypeInitializer<T: PyTypeInfo>(pub PhantomData<T>); |
27 | | - |
28 | | -impl<T: PyTypeInfo> PyObjectInit<T> for PyNativeTypeInitializer<T> { |
29 | | - unsafe fn into_new_object( |
30 | | - self, |
31 | | - py: Python<'_>, |
32 | | - subtype: *mut PyTypeObject, |
33 | | - ) -> PyResult<*mut ffi::PyObject> { |
34 | | - unsafe fn inner( |
35 | | - py: Python<'_>, |
36 | | - type_ptr: *mut PyTypeObject, |
37 | | - subtype: *mut PyTypeObject, |
38 | | - ) -> PyResult<*mut ffi::PyObject> { |
39 | | - let tp_new = unsafe { |
40 | | - type_ptr |
41 | | - .cast::<ffi::PyObject>() |
42 | | - .assume_borrowed_unchecked(py) |
43 | | - .cast_unchecked::<PyType>() |
44 | | - .get_slot(TP_NEW) |
45 | | - .ok_or_else(|| PyTypeError::new_err("base type without tp_new"))? |
46 | | - }; |
47 | | - |
48 | | - // TODO: make it possible to provide real arguments to the base tp_new |
49 | | - let obj = |
50 | | - unsafe { tp_new(subtype, PyTuple::empty(py).as_ptr(), core::ptr::null_mut()) }; |
51 | | - if obj.is_null() { |
52 | | - Err(PyErr::fetch(py)) |
53 | | - } else { |
54 | | - Ok(obj) |
55 | | - } |
56 | | - } |
57 | | - unsafe { inner(py, T::type_object_raw(py), subtype) } |
58 | | - } |
59 | | -} |
60 | | - |
61 | | -pub trait PyClassInit<'py, const IS_PYCLASS: bool, const IS_INITIALIZER_TUPLE: bool>: |
62 | | - seal_pyclass_init::Sealed<'py, IS_PYCLASS, IS_INITIALIZER_TUPLE> |
63 | | -{ |
64 | | - fn init( |
65 | | - self, |
66 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
67 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>>; |
68 | | -} |
69 | | - |
70 | | -mod seal_pyclass_init { |
71 | | - use crate::impl_::pyclass::{self, PyClassBaseType}; |
72 | | - use crate::impl_::pyclass_init::{PyClassInit, PyNativeTypeInitializer}; |
73 | | - use crate::{PyClass, PyClassInitializer, PyErr}; |
74 | | - |
75 | | - pub trait Sealed<'py, const IS_PYCLASS: bool, const IS_INITIALIZER_TUPLE: bool> {} |
76 | | - |
77 | | - impl<'py, T> Sealed<'py, false, false> for T where T: crate::IntoPyObject<'py> {} |
78 | | - impl<'py, T> Sealed<'py, true, false> for T |
79 | | - where |
80 | | - T: crate::PyClass, |
81 | | - T::BaseType: pyclass::PyClassBaseType<Initializer = PyNativeTypeInitializer<T::BaseType>>, |
82 | | - { |
83 | | - } |
84 | | - impl<'py, T, E, const IS_PYCLASS: bool, const IS_INITIALIZER_TUPLE: bool> |
85 | | - Sealed<'py, IS_PYCLASS, IS_INITIALIZER_TUPLE> for Result<T, E> |
86 | | - where |
87 | | - T: PyClassInit<'py, IS_PYCLASS, IS_INITIALIZER_TUPLE>, |
88 | | - E: Into<PyErr>, |
89 | | - { |
90 | | - } |
91 | | - impl<'py, T> Sealed<'py, false, false> for PyClassInitializer<T> where T: PyClass {} |
92 | | - impl<'py, S, B> Sealed<'py, false, true> for (S, B) |
93 | | - where |
94 | | - S: PyClass<BaseType = B>, |
95 | | - B: PyClass + PyClassBaseType<Initializer = PyClassInitializer<B>>, |
96 | | - B::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<B::BaseType>>, |
97 | | - { |
98 | | - } |
99 | | -} |
100 | | - |
101 | | -impl<'py, T> PyClassInit<'py, false, false> for T |
102 | | -where |
103 | | - T: crate::IntoPyObject<'py>, |
104 | | -{ |
105 | | - fn init( |
106 | | - self, |
107 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
108 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>> { |
109 | | - self.into_pyobject(cls.py()) |
110 | | - .map(crate::BoundObject::into_any) |
111 | | - .map(crate::BoundObject::into_bound) |
112 | | - .map_err(Into::into) |
113 | | - } |
114 | | -} |
115 | | - |
116 | | -impl<'py, T> PyClassInit<'py, true, false> for T |
117 | | -where |
118 | | - T: crate::PyClass, |
119 | | - T::BaseType: |
120 | | - super::pyclass::PyClassBaseType<Initializer = PyNativeTypeInitializer<T::BaseType>>, |
121 | | -{ |
122 | | - fn init( |
123 | | - self, |
124 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
125 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>> { |
126 | | - PyClassInitializer::from(self).init(cls) |
127 | | - } |
128 | | -} |
129 | | - |
130 | | -impl<'py, T, E, const IS_PYCLASS: bool, const IS_INITIALIZER_TUPLE: bool> |
131 | | - PyClassInit<'py, IS_PYCLASS, IS_INITIALIZER_TUPLE> for Result<T, E> |
132 | | -where |
133 | | - T: PyClassInit<'py, IS_PYCLASS, IS_INITIALIZER_TUPLE>, |
134 | | - E: Into<PyErr>, |
135 | | -{ |
136 | | - fn init( |
137 | | - self, |
138 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
139 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>> { |
140 | | - self.map_err(Into::into)?.init(cls) |
141 | | - } |
142 | | -} |
143 | | - |
144 | | -impl<'py, T> PyClassInit<'py, false, false> for PyClassInitializer<T> |
145 | | -where |
146 | | - T: PyClass, |
147 | | -{ |
148 | | - fn init( |
149 | | - self, |
150 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
151 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>> { |
152 | | - unsafe { |
153 | | - self.create_class_object_of_type(cls.py(), cls.as_ptr().cast()) |
154 | | - .map(crate::Bound::into_any) |
155 | | - } |
156 | | - } |
157 | | -} |
158 | | - |
159 | | -impl<'py, S, B> PyClassInit<'py, false, true> for (S, B) |
160 | | -where |
161 | | - S: PyClass<BaseType = B>, |
162 | | - B: PyClass + PyClassBaseType<Initializer = PyClassInitializer<B>>, |
163 | | - B::BaseType: PyClassBaseType<Initializer = PyNativeTypeInitializer<B::BaseType>>, |
164 | | -{ |
165 | | - fn init( |
166 | | - self, |
167 | | - cls: crate::Borrowed<'_, 'py, crate::types::PyType>, |
168 | | - ) -> PyResult<crate::Bound<'py, crate::PyAny>> { |
169 | | - let (sub, base) = self; |
170 | | - PyClassInitializer::from(base).add_subclass(sub).init(cls) |
171 | | - } |
172 | | -} |
| 1 | +/// Re-exported so that macros can name this internal type. |
| 2 | +pub use crate::internal::pyclass_init::PyNativeTypeInitializer; |
0 commit comments