Skip to content

Commit d0ddb78

Browse files
authored
add Sealed to pyclass traits (#5845)
1 parent e883df1 commit d0ddb78

1 file changed

Lines changed: 30 additions & 5 deletions

File tree

src/impl_/pyclass.rs

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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

@@ -971,7 +979,7 @@ pub trait PyClassInventory: inventory::Collect {
971979

972980
// Items from #[pymethods] if not using inventory.
973981
#[cfg(not(feature = "multiple-pymethods"))]
974-
pub trait PyMethods<T> {
982+
pub trait PyMethods<T>: pymethods::Sealed {
975983
fn py_methods(self) -> &'static PyClassItems;
976984
}
977985

@@ -985,6 +993,15 @@ impl<T> PyMethods<T> for &'_ PyClassImplCollector<T> {
985993
}
986994
}
987995

996+
mod pymethods {
997+
use crate::impl_::pyclass::PyClassImplCollector;
998+
999+
pub trait Sealed {}
1000+
1001+
impl<T> Sealed for &PyClassImplCollector<T> {}
1002+
impl<T> Sealed for PyClassImplCollector<T> {}
1003+
}
1004+
9881005
// Thread checkers
9891006

9901007
#[doc(hidden)]
@@ -1277,7 +1294,7 @@ where
12771294
label = "required by `#[pyo3(get)]` to create a readable property from a field of type `{Self}`",
12781295
note = "implement `IntoPyObject` for `&{Self}` or `IntoPyObject + Clone` for `{Self}` to define the conversion"
12791296
)]
1280-
pub trait PyO3GetField<'py>: IntoPyObject<'py> + Clone {}
1297+
pub trait PyO3GetField<'py>: IntoPyObject<'py> + Clone + pyo3_get_field::Sealed {}
12811298
impl<'py, T> PyO3GetField<'py> for T where T: IntoPyObject<'py> + Clone {}
12821299

12831300
/// Base case attempts to use IntoPyObject + Clone
@@ -1298,6 +1315,14 @@ impl<ClassT: PyClass, FieldT, const OFFSET: usize, const IMPLEMENTS_INTOPYOBJECT
12981315
}
12991316
}
13001317

1318+
mod pyo3_get_field {
1319+
use crate::IntoPyObject;
1320+
1321+
pub trait Sealed {}
1322+
1323+
impl<'py, T: IntoPyObject<'py>> Sealed for T {}
1324+
}
1325+
13011326
/// ensures `obj` is not mutably aliased
13021327
#[inline]
13031328
unsafe fn ensure_no_mutable_alias<'a, ClassT: PyClass>(
@@ -1413,7 +1438,7 @@ impl<const IMPLEMENTS_INTOPYOBJECT: bool> ConvertField<false, IMPLEMENTS_INTOPYO
14131438
}
14141439
}
14151440

1416-
pub trait ExtractPyClassWithClone {}
1441+
pub trait ExtractPyClassWithClone: generic_pyclass::Sealed {}
14171442

14181443
#[cfg(test)]
14191444
#[cfg(feature = "macros")]

0 commit comments

Comments
 (0)