Skip to content

Commit 40de57d

Browse files
committed
add Sealed to pyclass traits
1 parent 9072f6c commit 40de57d

File tree

1 file changed

+40
-7
lines changed

1 file changed

+40
-7
lines changed

src/impl_/pyclass.rs

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ unsafe impl Sync for PyClassItems {}
155155
///
156156
/// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail
157157
/// and may be changed at any time.
158-
pub trait PyClassImpl: Sized + 'static {
158+
pub trait PyClassImpl: Sized + 'static + generic_pyclass::Sealed {
159159
/// Module which the class will be associated with.
160160
///
161161
/// (Currently defaults to `builtins` if unset, this will likely be improved in the future, it
@@ -238,6 +238,14 @@ pub trait PyClassImpl: Sized + 'static {
238238
fn lazy_type_object() -> &'static LazyTypeObject<Self>;
239239
}
240240

241+
mod generic_pyclass {
242+
use crate::PyClass;
243+
244+
pub trait Sealed {}
245+
246+
impl<T: PyClass> Sealed for T {}
247+
}
248+
241249
/// Iterator used to process all class items during type instantiation.
242250
pub struct PyClassItemsIter {
243251
/// Iteration state
@@ -305,7 +313,7 @@ impl Iterator for PyClassItemsIter {
305313
macro_rules! slot_fragment_trait {
306314
($trait_name:ident, $($default_method:tt)*) => {
307315
#[allow(non_camel_case_types, reason = "to match Python dunder names")]
308-
pub trait $trait_name<T>: Sized {
316+
pub trait $trait_name<T>: Sized + pymethods::Sealed {
309317
$($default_method)*
310318
}
311319

@@ -896,7 +904,7 @@ pub use generate_pyclass_richcompare_slot;
896904
///
897905
/// Do not implement this trait manually. Instead, use `#[pyclass(freelist = N)]`
898906
/// on a Rust struct to implement it.
899-
pub trait PyClassWithFreeList: PyClass {
907+
pub trait PyClassWithFreeList: PyClass + generic_pyclass::Sealed {
900908
fn get_free_list(py: Python<'_>) -> &'static Mutex<PyObjectFreeList>;
901909
}
902910

@@ -1003,7 +1011,7 @@ pub trait PyClassInventory: inventory::Collect {
10031011

10041012
// Items from #[pymethods] if not using inventory.
10051013
#[cfg(not(feature = "multiple-pymethods"))]
1006-
pub trait PyMethods<T> {
1014+
pub trait PyMethods<T>: pymethods::Sealed {
10071015
fn py_methods(self) -> &'static PyClassItems;
10081016
}
10091017

@@ -1017,6 +1025,15 @@ impl<T> PyMethods<T> for &'_ PyClassImplCollector<T> {
10171025
}
10181026
}
10191027

1028+
mod pymethods {
1029+
use crate::impl_::pyclass::PyClassImplCollector;
1030+
1031+
pub trait Sealed {}
1032+
1033+
impl<T> Sealed for &PyClassImplCollector<T> {}
1034+
impl<T> Sealed for PyClassImplCollector<T> {}
1035+
}
1036+
10201037
// Thread checkers
10211038

10221039
#[doc(hidden)]
@@ -1109,7 +1126,7 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl {
11091126
note = "`{Self}` must have `#[pyclass(subclass)]` to be eligible for subclassing",
11101127
)
11111128
)]
1112-
pub trait PyClassBaseType: Sized {
1129+
pub trait PyClassBaseType: Sized + pyclass_base_type::Sealed {
11131130
type LayoutAsBase: PyClassObjectBaseLayout<Self>;
11141131
type BaseNativeType;
11151132
type Initializer: PyObjectInit<Self>;
@@ -1118,6 +1135,14 @@ pub trait PyClassBaseType: Sized {
11181135
type Layout<T: PyClassImpl>;
11191136
}
11201137

1138+
mod pyclass_base_type {
1139+
use crate::impl_::pyclass::PyClassBaseType;
1140+
1141+
pub trait Sealed {}
1142+
1143+
impl<T: PyClassBaseType> Sealed for T {}
1144+
}
1145+
11211146
/// Implementation of tp_dealloc for pyclasses without gc
11221147
pub(crate) unsafe extern "C" fn tp_dealloc<T: PyClass>(obj: *mut ffi::PyObject) {
11231148
unsafe { crate::impl_::trampoline::dealloc(obj, <T as PyClassImpl>::Layout::tp_dealloc) }
@@ -1303,7 +1328,7 @@ where
13031328
label = "required by `#[pyo3(get)]` to create a readable property from a field of type `{Self}`",
13041329
note = "implement `IntoPyObject` for `&{Self}` or `IntoPyObject + Clone` for `{Self}` to define the conversion"
13051330
)]
1306-
pub trait PyO3GetField<'py>: IntoPyObject<'py> + Clone {}
1331+
pub trait PyO3GetField<'py>: IntoPyObject<'py> + Clone + pyo3_get_field::Sealed {}
13071332
impl<'py, T> PyO3GetField<'py> for T where T: IntoPyObject<'py> + Clone {}
13081333

13091334
/// Base case attempts to use IntoPyObject + Clone
@@ -1324,6 +1349,14 @@ impl<ClassT: PyClass, FieldT, const OFFSET: usize, const IMPLEMENTS_INTOPYOBJECT
13241349
}
13251350
}
13261351

1352+
mod pyo3_get_field {
1353+
use crate::IntoPyObject;
1354+
1355+
pub trait Sealed {}
1356+
1357+
impl<'py, T: IntoPyObject<'py>> Sealed for T {}
1358+
}
1359+
13271360
/// ensures `obj` is not mutably aliased
13281361
#[inline]
13291362
unsafe fn ensure_no_mutable_alias<'a, ClassT: PyClass>(
@@ -1441,7 +1474,7 @@ impl<const IMPLEMENTS_INTOPYOBJECT: bool> ConvertField<false, IMPLEMENTS_INTOPYO
14411474
}
14421475
}
14431476

1444-
pub trait ExtractPyClassWithClone {}
1477+
pub trait ExtractPyClassWithClone: generic_pyclass::Sealed {}
14451478

14461479
#[cfg(test)]
14471480
#[cfg(feature = "macros")]

0 commit comments

Comments
 (0)