@@ -31,9 +31,9 @@ pub trait PySizedLayout<T>: PyLayout<T> + Sized {}
3131///
3232/// - `Py<Self>::as_ref` will hand out references to `Self::AsRefTarget`.
3333/// - `Self::AsRefTarget` must have the same layout as `UnsafeCell<ffi::PyAny>`.
34+ #[ cfg( feature = "gil-refs" ) ]
3435pub unsafe trait HasPyGilRef {
3536 /// Utility type to make Py::as_ref work.
36- #[ cfg( feature = "gil-refs" ) ]
3737 type AsRefTarget : PyNativeType ;
3838}
3939
4545 type AsRefTarget = Self ;
4646}
4747
48- #[ cfg( not( feature = "gil-refs" ) ) ]
49- unsafe impl < T > HasPyGilRef for T { }
50-
5148/// Python type information.
5249/// All Python native types (e.g., `PyDict`) and `#[pyclass]` structs implement this trait.
5350///
@@ -61,6 +58,7 @@ unsafe impl<T> HasPyGilRef for T {}
6158///
6259/// Implementations must provide an implementation for `type_object_raw` which infallibly produces a
6360/// non-null pointer to the corresponding Python type object.
61+ #[ cfg( feature = "gil-refs" ) ]
6462pub unsafe trait PyTypeInfo : Sized + HasPyGilRef {
6563 /// Class name.
6664 const NAME : & ' static str ;
@@ -139,7 +137,62 @@ pub unsafe trait PyTypeInfo: Sized + HasPyGilRef {
139137 }
140138}
141139
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+
142194/// Implemented by types which can be used as a concrete Python type inside `Py<T>` smart pointers.
195+ #[ cfg( feature = "gil-refs" ) ]
143196pub trait PyTypeCheck : HasPyGilRef {
144197 /// Name of self. This is used in error messages, for example.
145198 const NAME : & ' static str ;
@@ -150,6 +203,18 @@ pub trait PyTypeCheck: HasPyGilRef {
150203 fn type_check ( object : & Bound < ' _ , PyAny > ) -> bool ;
151204}
152205
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+
153218impl < T > PyTypeCheck for T
154219where
155220 T : PyTypeInfo ,
0 commit comments