Skip to content

Commit 2b83471

Browse files
committed
feature gate HasPyGilRef completely
1 parent 93aef75 commit 2b83471

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

src/instance.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use crate::err::{self, PyErr, PyResult};
22
use crate::impl_::pycell::PyClassObject;
33
use crate::pycell::{PyBorrowError, PyBorrowMutError};
44
use crate::pyclass::boolean_struct::{False, True};
5+
#[cfg(feature = "gil-refs")]
56
use crate::type_object::HasPyGilRef;
67
use crate::types::{any::PyAnyMethods, string::PyStringMethods, typeobject::PyTypeMethods};
78
use crate::types::{DerefToPyAny, PyDict, PyString, PyTuple};
@@ -667,11 +668,11 @@ impl<'a, 'py, T> From<&'a Bound<'py, T>> for Borrowed<'a, 'py, T> {
667668
}
668669
}
669670

671+
#[cfg(feature = "gil-refs")]
670672
impl<'py, T> Borrowed<'py, 'py, T>
671673
where
672674
T: HasPyGilRef,
673675
{
674-
#[cfg(feature = "gil-refs")]
675676
pub(crate) fn into_gil_ref(self) -> &'py T::AsRefTarget {
676677
// Safety: self is a borrow over `'py`.
677678
#[allow(deprecated)]
@@ -954,6 +955,7 @@ where
954955
}
955956
}
956957

958+
#[cfg(feature = "gil-refs")]
957959
impl<T> Py<T>
958960
where
959961
T: HasPyGilRef,
@@ -1001,7 +1003,6 @@ where
10011003
/// assert!(my_class_cell.try_borrow().is_ok());
10021004
/// });
10031005
/// ```
1004-
#[cfg(feature = "gil-refs")]
10051006
#[deprecated(
10061007
since = "0.21.0",
10071008
note = "use `obj.bind(py)` instead of `obj.as_ref(py)`"
@@ -1054,7 +1055,6 @@ where
10541055
/// obj.into_ref(py)
10551056
/// }
10561057
/// ```
1057-
#[cfg(feature = "gil-refs")]
10581058
#[deprecated(
10591059
since = "0.21.0",
10601060
note = "use `obj.into_bound(py)` instead of `obj.into_ref(py)`"

src/type_object.rs

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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")]
3435
pub unsafe trait HasPyGilRef {
3536
/// Utility type to make Py::as_ref work.
36-
#[cfg(feature = "gil-refs")]
3737
type AsRefTarget: PyNativeType;
3838
}
3939

@@ -45,9 +45,6 @@ where
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")]
6462
pub 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")]
143196
pub 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+
153218
impl<T> PyTypeCheck for T
154219
where
155220
T: PyTypeInfo,

0 commit comments

Comments
 (0)