diff --git a/pyo3-macros-backend/src/pyclass.rs b/pyo3-macros-backend/src/pyclass.rs index 21b8c2dd..2162b684 100644 --- a/pyo3-macros-backend/src/pyclass.rs +++ b/pyo3-macros-backend/src/pyclass.rs @@ -637,6 +637,7 @@ impl<'a> PyClassImplsBuilder<'a> { type Dict = #dict; type WeakRef = #weakref; type BaseNativeType = #base_nativetype; + type Mutability = ::pyo3::pycell::Immutable; } } } @@ -763,8 +764,8 @@ impl<'a> PyClassImplsBuilder<'a> { let mutability = if self.attr.is_immutable { quote! { - ::pyo3::pycell::Immutable - } + ::pyo3::pycell::Immutable + } } else { quote! { ::pyo3::pycell::Mutable @@ -781,7 +782,6 @@ impl<'a> PyClassImplsBuilder<'a> { type Layout = ::pyo3::PyCell; type BaseType = #base; type ThreadChecker = #thread_checker; - type Mutability= #mutability; fn for_each_method_def(visitor: &mut dyn ::std::ops::FnMut(&[::pyo3::class::PyMethodDefType])) { use ::pyo3::class::impl_::*; @@ -839,8 +839,8 @@ impl<'a> PyClassImplsBuilder<'a> { let cls = self.cls; if self.attr.is_immutable { quote! { - unsafe impl ::pyo3::pyclass::ImmutablePyClass for #cls {} - } + unsafe impl ::pyo3::pyclass::ImmutablePyClass for #cls {} + } } else { quote! { unsafe impl ::pyo3::pyclass::MutablePyClass for #cls {} diff --git a/src/class/impl_.rs b/src/class/impl_.rs index b77fe57b..ea0f8ee8 100644 --- a/src/class/impl_.rs +++ b/src/class/impl_.rs @@ -4,7 +4,7 @@ use crate::{ exceptions::{PyAttributeError, PyNotImplementedError}, ffi, impl_::freelist::FreeList, - pycell::{PyCellLayout, Mutability}, + pycell::{Mutability, PyCellLayout}, pyclass_init::PyObjectInit, type_object::{PyLayout, PyTypeObject}, PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python, @@ -39,7 +39,7 @@ impl Copy for PyClassImplCollector {} /// /// Users are discouraged from implementing this trait manually; it is a PyO3 implementation detail /// and may be changed at any time. -pub trait PyClassImpl: Sized { +pub trait PyClassImpl: Sized { /// Class doc string const DOC: &'static str = "\0"; @@ -56,7 +56,7 @@ pub trait PyClassImpl: Sized { type Layout: PyLayout; /// Base class - type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType; + type BaseType: PyTypeInfo + PyTypeObject + PyClassBaseType; /// This handles following two situations: /// 1. In case `T` is `Send`, stub `ThreadChecker` is used and does nothing. @@ -67,8 +67,6 @@ pub trait PyClassImpl: Sized { /// can be accessed by multiple threads by `threading` module. type ThreadChecker: PyClassThreadChecker; - type Mutability: crate::pycell::Mutability; - fn for_each_method_def(_visitor: &mut dyn FnMut(&[PyMethodDefType])) {} fn get_new() -> Option { None @@ -749,9 +747,14 @@ impl PyClassThreadChecker for ThreadCheckerImpl { /// Thread checker for types that have `Send` and `extends=...`. /// Ensures that `T: Send` and the parent is not accessed by another thread. #[doc(hidden)] -pub struct ThreadCheckerInherited(PhantomData, U::ThreadChecker); +pub struct ThreadCheckerInherited, M: Mutability>( + PhantomData, + U::ThreadChecker, +); -impl PyClassThreadChecker for ThreadCheckerInherited { +impl, M: Mutability> PyClassThreadChecker + for ThreadCheckerInherited +{ fn ensure(&self) { self.1.ensure(); } @@ -762,25 +765,23 @@ impl PyClassThreadChecker for ThreadCheckerInher } /// Trait denoting that this class is suitable to be used as a base type for PyClass. -pub trait PyClassBaseType: Sized { +pub trait PyClassBaseType: Sized { type Dict; type WeakRef; - type LayoutAsBase: PyCellLayout; + type LayoutAsBase: PyCellLayout; type BaseNativeType; type ThreadChecker: PyClassThreadChecker; type Initializer: PyObjectInit; - type Mutability: Mutability; } /// All PyClasses can be used as a base type. -impl PyClassBaseType for T { +impl PyClassBaseType for T { type Dict = T::Dict; type WeakRef = T::WeakRef; type LayoutAsBase = crate::pycell::PyCell; type BaseNativeType = T::BaseNativeType; type ThreadChecker = T::ThreadChecker; type Initializer = crate::pyclass_init::PyClassInitializer; - type Mutability = T::Mutability; } /// Default new implementation diff --git a/src/pycell.rs b/src/pycell.rs index 57fe8eeb..9b696406 100644 --- a/src/pycell.rs +++ b/src/pycell.rs @@ -174,6 +174,7 @@ //! [guide]: https://pyo3.rs/latest/class.html#pycell-and-interior-mutability "PyCell and interior mutability" //! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell and the Interior Mutability Pattern - The Rust Programming Language" +use crate::class::impl_::PyClassImpl; use crate::exceptions::PyRuntimeError; use crate::pyclass::{MutablePyClass, PyClass}; use crate::pyclass_init::PyClassInitializer; @@ -181,7 +182,6 @@ use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::type_object::{PyLayout, PySizedLayout}; use crate::types::PyAny; use crate::{class::impl_::PyClassBaseType, class::impl_::PyClassThreadChecker}; -use crate::class::impl_::PyClassImpl; use crate::{ conversion::{AsPyPointer, FromPyPointer, ToPyObject}, ffi::PyBaseObject_Type, @@ -191,9 +191,9 @@ use crate::{ use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python}; use std::cell::{Cell, UnsafeCell}; use std::fmt; +use std::marker::PhantomData; use std::mem::ManuallyDrop; use std::ops::{Deref, DerefMut}; -use std::marker::PhantomData; pub trait Mutability { /// Creates a new borrow checker @@ -202,7 +202,7 @@ pub trait Mutability { fn try_borrow(&self) -> Result<(), PyBorrowError>; fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError>; - + /// Decrements immutable borrow count fn release_borrow(&self); /// Increments mutable borrow count, if possible @@ -215,76 +215,74 @@ pub struct Mutable { flag: Cell, } impl Mutability for Mutable { - fn new() -> Self{ - Self{flag: Cell::new(BorrowFlag::UNUSED)} + fn new() -> Self { + Self { + flag: Cell::new(BorrowFlag::UNUSED), + } } - fn try_borrow(&self) -> Result<(), PyBorrowError>{ + fn try_borrow(&self) -> Result<(), PyBorrowError> { let flag = self.flag.get(); if flag != BorrowFlag::HAS_MUTABLE_BORROW { self.flag.set(flag.increment()); Ok(()) - } - else{ + } else { Err(PyBorrowError { _private: () }) } } - fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError>{ + fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> { let flag = self.flag.get(); if flag != BorrowFlag::HAS_MUTABLE_BORROW { Ok(()) - } - else{ + } else { Err(PyBorrowError { _private: () }) } } - fn release_borrow(&self){ + fn release_borrow(&self) { let flag = self.flag.get(); self.flag.set(flag.decrement()) } - fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError>{ + fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> { let flag = self.flag.get(); if flag == BorrowFlag::UNUSED { self.flag.set(BorrowFlag::HAS_MUTABLE_BORROW); Ok(()) - } - else{ + } else { Err(PyBorrowMutError { _private: () }) } } - fn release_borrow_mut(&self){ + fn release_borrow_mut(&self) { self.flag.set(BorrowFlag::UNUSED) } } -pub struct Immutable{ - flag: PhantomData> +pub struct Immutable { + flag: PhantomData>, } impl Mutability for Immutable { - fn new() -> Self{ - Self{flag: PhantomData} + fn new() -> Self { + Self { flag: PhantomData } } - fn try_borrow(&self) -> Result<(), PyBorrowError>{ - Ok(()) - } - - fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError>{ + fn try_borrow(&self) -> Result<(), PyBorrowError> { Ok(()) } - fn release_borrow(&self){ + fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> { + Ok(()) } - fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError>{ + fn release_borrow(&self) {} + + fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> { unreachable!() } - fn release_borrow_mut(&self){ + fn release_borrow_mut(&self) { unreachable!() } } @@ -298,7 +296,12 @@ pub struct PyCellBase { borrow_impl: M, } -unsafe impl PyLayout for PyCellBase where U: PySizedLayout, M: Mutability {} +unsafe impl PyLayout for PyCellBase +where + U: PySizedLayout, + M: Mutability, +{ +} /// A container type for (mutably) accessing [`PyClass`] values /// @@ -337,7 +340,7 @@ unsafe impl PyLayout for PyCellBase where U: PySizedLayout, /// [module-level documentation](self). #[repr(C)] pub struct PyCell { - ob_base: ::LayoutAsBase, + ob_base: >::LayoutAsBase, contents: PyCellContents, } @@ -491,7 +494,9 @@ impl PyCell { /// }); /// ``` pub fn try_borrow(&self) -> Result, PyBorrowError> { - self.borrow_checker().try_borrow().map(|_| PyRef { inner: self }) + self.borrow_checker() + .try_borrow() + .map(|_| PyRef { inner: self }) } /// Mutably borrows the value `T`, returning an error if the value is currently borrowed. @@ -519,7 +524,9 @@ impl PyCell { where T: MutablePyClass, { - self.borrow_checker().try_borrow_mut().map(|_| PyRefMut { inner: self }) + self.borrow_checker() + .try_borrow_mut() + .map(|_| PyRefMut { inner: self }) } /// Immutably borrows the value `T`, returning an error if the value is @@ -552,7 +559,9 @@ impl PyCell { /// }); /// ``` pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> { - self.borrow_checker().try_borrow_unguarded().map(|_:()| &*self.contents.value.get()) + self.borrow_checker() + .try_borrow_unguarded() + .map(|_: ()| &*self.contents.value.get()) } /// Replaces the wrapped value with a new one, returning the old value. @@ -976,8 +985,11 @@ impl From for PyErr { } #[doc(hidden)] -pub trait PyCellLayout: PyLayout { - fn borrow_checker(&self) -> &T::Mutability where T: PyClass; +pub trait PyCellLayout: PyLayout +where + M: Mutability, +{ + fn borrow_checker(&self) -> &M; /// Implementation of tp_dealloc. /// # Safety /// - slf must be a valid pointer to an instance of a T or a subclass. @@ -985,14 +997,13 @@ pub trait PyCellLayout: PyLayout { unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python); } -impl PyCellLayout for PyCellBase +impl PyCellLayout for PyCellBase where U: PySizedLayout, T: PyTypeInfo, - M: Mutability - + M: Mutability, { - fn borrow_checker(&self) -> &T::Mutability where T: PyClass{ + fn borrow_checker(&self) -> &M { &self.borrow_impl } @@ -1017,11 +1028,12 @@ where } } -impl PyCellLayout for PyCell +impl PyCellLayout for PyCell where - ::LayoutAsBase: PyCellLayout, + >::LayoutAsBase: + PyCellLayout, { - fn borrow_checker(&self) -> &T ::Mutability { + fn borrow_checker(&self) -> &T::Mutability { self.contents.thread_checker.ensure(); self.ob_base.borrow_checker() } @@ -1031,6 +1043,6 @@ where ManuallyDrop::drop(&mut cell.contents.value); cell.contents.dict.clear_dict(py); cell.contents.weakref.clear_weakrefs(slf, py); - ::LayoutAsBase::tp_dealloc(slf, py) + >::LayoutAsBase::tp_dealloc(slf, py) } } diff --git a/src/pyclass.rs b/src/pyclass.rs index 886333d4..67dfc885 100644 --- a/src/pyclass.rs +++ b/src/pyclass.rs @@ -1,11 +1,11 @@ //! `PyClass` and related traits. +use crate::pycell::Mutability; use crate::{ class::impl_::{fallback_new, tp_dealloc, PyClassImpl}, ffi, pyclass_slots::{PyClassDict, PyClassWeakRef}, PyCell, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python, }; -use crate::pycell::Mutability; use std::{ convert::TryInto, ffi::CString, @@ -19,7 +19,7 @@ use std::{ /// The `#[pyclass]` attribute automatically implements this trait for your Rust struct, /// so you normally don't have to use this trait directly. pub trait PyClass: - PyTypeInfo> + PyClassImpl> + PyTypeInfo> + PyClassImpl> { /// Specify this class has `#[pyclass(dict)]` or not. type Dict: PyClassDict; @@ -29,7 +29,7 @@ pub trait PyClass: /// `#[pyclass(extends=PyDict)]`, it's `PyDict`. type BaseNativeType: PyTypeInfo + PyNativeType; - //type Mutability: Mutability; + type Mutability: Mutability; } pub unsafe trait MutablePyClass: PyClass {} diff --git a/src/pyclass_init.rs b/src/pyclass_init.rs index 20ca795b..7ce0fe9b 100644 --- a/src/pyclass_init.rs +++ b/src/pyclass_init.rs @@ -127,14 +127,17 @@ impl PyObjectInit for PyNativeTypeInitializer { /// ``` pub struct PyClassInitializer { init: T, - super_init: ::Initializer, + super_init: >::Initializer, } impl PyClassInitializer { /// Constructs a new initializer from value `T` and base class' initializer. /// /// It is recommended to use `add_subclass` instead of this method for most usage. - pub fn new(init: T, super_init: ::Initializer) -> Self { + pub fn new( + init: T, + super_init: >::Initializer, + ) -> Self { Self { init, super_init } } @@ -187,7 +190,7 @@ impl PyClassInitializer { pub fn add_subclass(self, subclass_value: S) -> PyClassInitializer where S: PyClass, - S::BaseType: PyClassBaseType, + S::BaseType: PyClassBaseType, { PyClassInitializer::new(subclass_value, self) } @@ -228,16 +231,16 @@ impl PyObjectInit for PyClassInitializer { /// Layout of a PyCellBase after base new has been called, but the borrow flag has not /// yet been initialized. #[repr(C)] - struct PartiallyInitializedPyCellBase { + struct PartiallyInitializedPyCellBase { _ob_base: T, - borrow_flag: MaybeUninit>, + borrow_flag: MaybeUninit, } /// Layout of a PyCell after base new has been called, but the contents have not yet been /// written. #[repr(C)] struct PartiallyInitializedPyCell { - _ob_base: ::LayoutAsBase, + _ob_base: >::LayoutAsBase, contents: MaybeUninit>, } @@ -271,7 +274,7 @@ impl PyObjectInit for PyClassInitializer { impl From for PyClassInitializer where T: PyClass, - T::BaseType: PyClassBaseType>, + T::BaseType: PyClassBaseType>, { #[inline] fn from(value: T) -> PyClassInitializer { @@ -283,7 +286,7 @@ impl From<(S, B)> for PyClassInitializer where S: PyClass, B: PyClass, - B::BaseType: PyClassBaseType>, + B::BaseType: PyClassBaseType>, { fn from(sub_and_base: (S, B)) -> PyClassInitializer { let (sub, base) = sub_and_base; diff --git a/src/types/mod.rs b/src/types/mod.rs index 289dac36..14db301c 100644 --- a/src/types/mod.rs +++ b/src/types/mod.rs @@ -195,14 +195,13 @@ macro_rules! pyobject_native_type_sized { ($name:ty, $layout:path $(;$generics:ident)*) => { unsafe impl $crate::type_object::PyLayout<$name> for $layout {} impl $crate::type_object::PySizedLayout<$name> for $layout {} - impl<'a, $($generics,)*> $crate::class::impl_::PyClassBaseType for $name { + impl<'a, $($generics,)*> $crate::class::impl_::PyClassBaseType<$crate::pycell::Mutable> for $name { type Dict = $crate::pyclass_slots::PyClassDummySlot; type WeakRef = $crate::pyclass_slots::PyClassDummySlot; type LayoutAsBase = $crate::pycell::PyCellBase<$layout, $crate::pycell::Mutable>; type BaseNativeType = $name; type ThreadChecker = $crate::class::impl_::ThreadCheckerStub<$crate::PyObject>; type Initializer = $crate::pyclass_init::PyNativeTypeInitializer; - type Mutability = $crate::pycell::Mutable; } } }