@@ -31,9 +31,9 @@ pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
31
31
///
32
32
/// - `Py<Self>::as_ref` will hand out references to `Self::AsRefTarget`.
33
33
/// - `Self::AsRefTarget` must have the same layout as `UnsafeCell<ffi::PyAny>`.
34
+ #[ cfg( feature = "gil-refs" ) ]
34
35
pub unsafe trait HasPyGilRef {
35
36
/// Utility type to make Py::as_ref work.
36
- #[ cfg( feature = "gil-refs" ) ]
37
37
type AsRefTarget : PyNativeType ;
38
38
}
39
39
45
45
type AsRefTarget = Self ;
46
46
}
47
47
48
- #[ cfg( not( feature = "gil-refs" ) ) ]
49
- unsafe impl < T > HasPyGilRef for T { }
50
-
51
48
/// Python type information.
52
49
/// All Python native types (e.g., `PyDict`) and `#[pyclass]` structs implement this trait.
53
50
///
@@ -61,6 +58,7 @@ unsafe impl<T> HasPyGilRef for T {}
61
58
///
62
59
/// Implementations must provide an implementation for `type_object_raw` which infallibly produces a
63
60
/// non-null pointer to the corresponding Python type object.
61
+ #[ cfg( feature = "gil-refs" ) ]
64
62
pub unsafe trait PyTypeInfo : Sized + HasPyGilRef {
65
63
/// Class name.
66
64
const NAME : & ' static str ;
@@ -139,7 +137,62 @@ pub unsafe trait PyTypeInfo: Sized + HasPyGilRef {
139
137
}
140
138
}
141
139
140
+ /// Python type information.
141
+ /// All Python native types (e.g., `PyDict`) and `#[pyclass]` structs implement this trait.
142
+ ///
143
+ /// This trait is marked unsafe because:
144
+ /// - specifying the incorrect layout can lead to memory errors
145
+ /// - the return value of type_object must always point to the same PyTypeObject instance
146
+ ///
147
+ /// It is safely implemented by the `pyclass` macro.
148
+ ///
149
+ /// # Safety
150
+ ///
151
+ /// Implementations must provide an implementation for `type_object_raw` which infallibly produces a
152
+ /// non-null pointer to the corresponding Python type object.
153
+ #[ cfg( not( feature = "gil-refs" ) ) ]
154
+ pub unsafe trait PyTypeInfo : Sized {
155
+ /// Class name.
156
+ const NAME : & ' static str ;
157
+
158
+ /// Module name, if any.
159
+ const MODULE : Option < & ' static str > ;
160
+
161
+ /// Returns the PyTypeObject instance for this type.
162
+ fn type_object_raw ( py : Python < ' _ > ) -> * mut ffi:: PyTypeObject ;
163
+
164
+ /// Returns the safe abstraction over the type object.
165
+ #[ inline]
166
+ fn type_object_bound ( py : Python < ' _ > ) -> Bound < ' _ , PyType > {
167
+ // Making the borrowed object `Bound` is necessary for soundness reasons. It's an extreme
168
+ // edge case, but arbitrary Python code _could_ change the __class__ of an object and cause
169
+ // the type object to be freed.
170
+ //
171
+ // By making `Bound` we assume ownership which is then safe against races.
172
+ unsafe {
173
+ Self :: type_object_raw ( py)
174
+ . cast :: < ffi:: PyObject > ( )
175
+ . assume_borrowed_unchecked ( py)
176
+ . to_owned ( )
177
+ . downcast_into_unchecked ( )
178
+ }
179
+ }
180
+
181
+ /// Checks if `object` is an instance of this type or a subclass of this type.
182
+ #[ inline]
183
+ fn is_type_of_bound ( object : & Bound < ' _ , PyAny > ) -> bool {
184
+ unsafe { ffi:: PyObject_TypeCheck ( object. as_ptr ( ) , Self :: type_object_raw ( object. py ( ) ) ) != 0 }
185
+ }
186
+
187
+ /// Checks if `object` is an instance of this type.
188
+ #[ inline]
189
+ fn is_exact_type_of_bound ( object : & Bound < ' _ , PyAny > ) -> bool {
190
+ unsafe { ffi:: Py_TYPE ( object. as_ptr ( ) ) == Self :: type_object_raw ( object. py ( ) ) }
191
+ }
192
+ }
193
+
142
194
/// Implemented by types which can be used as a concrete Python type inside `Py<T>` smart pointers.
195
+ #[ cfg( feature = "gil-refs" ) ]
143
196
pub trait PyTypeCheck : HasPyGilRef {
144
197
/// Name of self. This is used in error messages, for example.
145
198
const NAME : & ' static str ;
@@ -150,6 +203,18 @@ pub trait PyTypeCheck: HasPyGilRef {
150
203
fn type_check ( object : & Bound < ' _ , PyAny > ) -> bool ;
151
204
}
152
205
206
+ /// Implemented by types which can be used as a concrete Python type inside `Py<T>` smart pointers.
207
+ #[ cfg( not( feature = "gil-refs" ) ) ]
208
+ pub trait PyTypeCheck {
209
+ /// Name of self. This is used in error messages, for example.
210
+ const NAME : & ' static str ;
211
+
212
+ /// Checks if `object` is an instance of `Self`, which may include a subtype.
213
+ ///
214
+ /// This should be equivalent to the Python expression `isinstance(object, Self)`.
215
+ fn type_check ( object : & Bound < ' _ , PyAny > ) -> bool ;
216
+ }
217
+
153
218
impl < T > PyTypeCheck for T
154
219
where
155
220
T : PyTypeInfo ,
0 commit comments