Skip to content

Commit e9bd41e

Browse files
committed
better mutability inheritance rules
1 parent 7118e94 commit e9bd41e

12 files changed

+555
-142
lines changed

guide/src/class.md

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -956,13 +956,7 @@ unsafe impl ::pyo3::type_object::PyTypeInfo for MyClass {
956956
}
957957
}
958958

959-
impl ::pyo3::PyClass for MyClass {
960-
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
961-
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
962-
type BaseNativeType = ::pyo3::PyAny;
963-
}
964-
965-
unsafe impl ::pyo3::pyclass::MutablePyClass for MyClass {}
959+
impl ::pyo3::PyClass for MyClass { }
966960

967961
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut MyClass {
968962
type Target = ::pyo3::PyRefMut<'a, MyClass>;
@@ -985,7 +979,11 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
985979
type Layout = PyCell<MyClass>;
986980
type BaseType = PyAny;
987981
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
988-
type Mutabilty = pyo3::pyclass::Mutable;
982+
type Mutability = pyo3::pycell::Mutable;
983+
type PyClassMutability = pyo3::pycell::MutableClass;
984+
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
985+
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
986+
type BaseNativeType = ::pyo3::PyAny;
989987

990988
fn for_all_items(visitor: &mut dyn FnMut(&pyo3::impl_::pyclass::PyClassItems)) {
991989
use pyo3::impl_::pyclass::*;
@@ -996,14 +994,6 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
996994
}
997995
}
998996

999-
impl ::pyo3::impl_::pyclass::PyClassDescriptors<MyClass>
1000-
for ::pyo3::impl_::pyclass::PyClassImplCollector<MyClass>
1001-
{
1002-
fn py_class_descriptors(self) -> &'static [::pyo3::class::methods::PyMethodDefType] {
1003-
static METHODS: &[::pyo3::class::methods::PyMethodDefType] = &[];
1004-
METHODS
1005-
}
1006-
}
1007997
# Python::with_gil(|py| {
1008998
# let cls = py.get_type::<MyClass>();
1009999
# pyo3::py_run!(py, cls, "assert cls.__name__ == 'MyClass'")

pyo3-macros-backend/src/pyclass.rs

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -689,32 +689,9 @@ impl<'a> PyClassImplsBuilder<'a> {
689689

690690
fn impl_pyclass(&self) -> TokenStream {
691691
let cls = self.cls;
692-
let attr = self.attr;
693-
let dict = if attr.options.dict.is_some() {
694-
quote! { _pyo3::impl_::pyclass::PyClassDictSlot }
695-
} else {
696-
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
697-
};
698-
699-
// insert space for weak ref
700-
let weakref = if attr.options.weakref.is_some() {
701-
quote! { _pyo3::impl_::pyclass::PyClassWeakRefSlot }
702-
} else {
703-
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
704-
};
705-
706-
let base_nativetype = if attr.options.extends.is_some() {
707-
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType<Self::Mutability>>::BaseNativeType }
708-
} else {
709-
quote! { _pyo3::PyAny }
710-
};
711692

712693
quote! {
713-
impl _pyo3::PyClass for #cls {
714-
type Dict = #dict;
715-
type WeakRef = #weakref;
716-
type BaseNativeType = #base_nativetype;
717-
}
694+
impl _pyo3::PyClass for #cls { }
718695
}
719696
}
720697
fn impl_extractext(&self) -> TokenStream {
@@ -856,6 +833,37 @@ impl<'a> PyClassImplsBuilder<'a> {
856833
}
857834
};
858835

836+
let class_mutability = if self.attr.options.immutable.is_some() {
837+
quote! {
838+
ImmutableChild
839+
}
840+
} else {
841+
quote! {
842+
MutableChild
843+
}
844+
};
845+
846+
let cls = self.cls;
847+
let attr = self.attr;
848+
let dict = if attr.options.dict.is_some() {
849+
quote! { _pyo3::impl_::pyclass::PyClassDictSlot }
850+
} else {
851+
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
852+
};
853+
854+
// insert space for weak ref
855+
let weakref = if attr.options.weakref.is_some() {
856+
quote! { _pyo3::impl_::pyclass::PyClassWeakRefSlot }
857+
} else {
858+
quote! { _pyo3::impl_::pyclass::PyClassDummySlot }
859+
};
860+
861+
let base_nativetype = if attr.options.extends.is_some() {
862+
quote! { <Self::BaseType as _pyo3::impl_::pyclass::PyClassBaseType>::BaseNativeType }
863+
} else {
864+
quote! { _pyo3::PyAny }
865+
};
866+
859867
quote! {
860868
impl _pyo3::impl_::pyclass::PyClassImpl for #cls {
861869
const DOC: &'static str = #doc;
@@ -868,6 +876,10 @@ impl<'a> PyClassImplsBuilder<'a> {
868876
type ThreadChecker = #thread_checker;
869877
#inventory
870878
type Mutability = #mutability;
879+
type PyClassMutability = <<#base as _pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as _pyo3::pycell::PyClassMutability>::#class_mutability;
880+
type Dict = #dict;
881+
type WeakRef = #weakref;
882+
type BaseNativeType = #base_nativetype;
871883

872884
fn for_all_items(visitor: &mut dyn ::std::ops::FnMut(& _pyo3::impl_::pyclass::PyClassItems)) {
873885
use _pyo3::impl_::pyclass::*;

src/impl_/pyclass.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ use crate::{
22
exceptions::{PyAttributeError, PyNotImplementedError},
33
ffi,
44
impl_::freelist::FreeList,
5-
pycell::{Mutability, Mutable, PyCellLayout},
6-
pyclass::MutablePyClass,
5+
pycell::{GetBorrowChecker, Mutability, PyCellLayout, PyClassMutability},
76
pyclass_init::PyObjectInit,
87
type_object::{PyLayout, PyTypeObject},
98
Py, PyAny, PyCell, PyClass, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
@@ -163,11 +162,24 @@ pub trait PyClassImpl: Sized {
163162
type Layout: PyLayout<Self>;
164163

165164
/// Base class
166-
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType<Self::Mutability>;
165+
type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType;
167166

168167
/// Immutable or mutable
169168
type Mutability: Mutability;
170169

170+
/// Immutable or mutable
171+
type PyClassMutability: PyClassMutability + GetBorrowChecker<Self>;
172+
173+
/// Specify this class has `#[pyclass(dict)]` or not.
174+
type Dict: PyClassDict;
175+
176+
/// Specify this class has `#[pyclass(weakref)]` or not.
177+
type WeakRef: PyClassWeakRef;
178+
179+
/// The closest native ancestor. This is `PyAny` by default, and when you declare
180+
/// `#[pyclass(extends=PyDict)]`, it's `PyDict`.
181+
type BaseNativeType: PyTypeInfo + PyNativeType;
182+
171183
/// This handles following two situations:
172184
/// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing.
173185
/// This implementation is used by default. Compile fails if `T: !Send`.
@@ -870,12 +882,12 @@ impl<T> PyClassThreadChecker<T> for ThreadCheckerImpl<T> {
870882
/// Thread checker for types that have `Send` and `extends=...`.
871883
/// Ensures that `T: Send` and the parent is not accessed by another thread.
872884
#[doc(hidden)]
873-
pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType<T::Mutability>>(
885+
pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType>(
874886
PhantomData<T>,
875887
U::ThreadChecker,
876888
);
877889

878-
impl<T: PyClass + Send, U: PyClassBaseType<T::Mutability>> PyClassThreadChecker<T>
890+
impl<T: PyClass + Send, U: PyClassBaseType> PyClassThreadChecker<T>
879891
for ThreadCheckerInherited<T, U>
880892
{
881893
fn ensure(&self) {
@@ -888,21 +900,23 @@ impl<T: PyClass + Send, U: PyClassBaseType<T::Mutability>> PyClassThreadChecker<
888900
}
889901

890902
/// Trait denoting that this class is suitable to be used as a base type for PyClass.
891-
pub trait PyClassBaseType<M: Mutability>: Sized {
892-
type LayoutAsBase: PyCellLayout<Self, M>;
903+
pub trait PyClassBaseType: Sized {
904+
type LayoutAsBase: PyCellLayout<Self>;
893905
type BaseNativeType;
894906
type ThreadChecker: PyClassThreadChecker<Self>;
895907
type Initializer: PyObjectInit<Self>;
908+
type PyClassMutability: PyClassMutability;
896909
}
897910

898911
/// All mutable PyClasses can be used as a base type.
899912
///
900913
/// In the future this will be extended to immutable PyClasses too.
901-
impl<T: MutablePyClass> PyClassBaseType<Mutable> for T {
914+
impl<T: PyClass> PyClassBaseType for T {
902915
type LayoutAsBase = crate::pycell::PyCell<T>;
903916
type BaseNativeType = T::BaseNativeType;
904917
type ThreadChecker = T::ThreadChecker;
905918
type Initializer = crate::pyclass_init::PyClassInitializer<Self>;
919+
type PyClassMutability = T::PyClassMutability;
906920
}
907921

908922
/// Implementation of tp_dealloc for all pyclasses

0 commit comments

Comments
 (0)