Merge pull request #2570 from davidhewitt/pyclass-frozen-tidy
pyclass: tidy up frozen implementation
This commit is contained in:
commit
d0492b7c72
|
@ -1000,7 +1000,7 @@ impl pyo3::impl_::pyclass::PyClassImpl for MyClass {
|
||||||
type Layout = PyCell<MyClass>;
|
type Layout = PyCell<MyClass>;
|
||||||
type BaseType = PyAny;
|
type BaseType = PyAny;
|
||||||
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
type ThreadChecker = pyo3::impl_::pyclass::ThreadCheckerStub<MyClass>;
|
||||||
type PyClassMutability = pyo3::pycell::MutableClass;
|
type PyClassMutability = <<pyo3::PyAny as pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as pyo3::impl_::pycell::PyClassMutability>::MutableChild;
|
||||||
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
type Dict = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
||||||
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
type WeakRef = ::pyo3::impl_::pyclass::PyClassDummySlot;
|
||||||
type BaseNativeType = ::pyo3::PyAny;
|
type BaseNativeType = ::pyo3::PyAny;
|
||||||
|
|
|
@ -125,7 +125,7 @@ fn insert_lifetime(ty: &mut syn::Type) {
|
||||||
match ty {
|
match ty {
|
||||||
syn::Type::Reference(ref mut r) => {
|
syn::Type::Reference(ref mut r) => {
|
||||||
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
r.lifetime.get_or_insert(syn::parse_quote! {'p});
|
||||||
insert_lifetime(&mut *r.elem);
|
insert_lifetime(&mut r.elem);
|
||||||
}
|
}
|
||||||
syn::Type::Path(ref mut path) => insert_lifetime_for_path(path),
|
syn::Type::Path(ref mut path) => insert_lifetime_for_path(path),
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
|
@ -773,9 +773,15 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
fn impl_pyclass(&self) -> TokenStream {
|
fn impl_pyclass(&self) -> TokenStream {
|
||||||
let cls = self.cls;
|
let cls = self.cls;
|
||||||
|
|
||||||
|
let frozen = if self.attr.options.frozen.is_some() {
|
||||||
|
quote! { _pyo3::pyclass::boolean_struct::True }
|
||||||
|
} else {
|
||||||
|
quote! { _pyo3::pyclass::boolean_struct::False }
|
||||||
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
impl _pyo3::PyClass for #cls {
|
impl _pyo3::PyClass for #cls {
|
||||||
type Frozen = <Self::PyClassMutability as _pyo3::pycell::PyClassMutability>::Frozen;
|
type Frozen = #frozen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -983,7 +989,7 @@ impl<'a> PyClassImplsBuilder<'a> {
|
||||||
type BaseType = #base;
|
type BaseType = #base;
|
||||||
type ThreadChecker = #thread_checker;
|
type ThreadChecker = #thread_checker;
|
||||||
#inventory
|
#inventory
|
||||||
type PyClassMutability = <<#base as _pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as _pyo3::pycell::PyClassMutability>::#class_mutability;
|
type PyClassMutability = <<#base as _pyo3::impl_::pyclass::PyClassBaseType>::PyClassMutability as _pyo3::impl_::pycell::PyClassMutability>::#class_mutability;
|
||||||
type Dict = #dict;
|
type Dict = #dict;
|
||||||
type WeakRef = #weakref;
|
type WeakRef = #weakref;
|
||||||
type BaseNativeType = #base_nativetype;
|
type BaseNativeType = #base_nativetype;
|
||||||
|
|
|
@ -7,15 +7,12 @@
|
||||||
pub mod deprecations;
|
pub mod deprecations;
|
||||||
pub mod extract_argument;
|
pub mod extract_argument;
|
||||||
pub mod freelist;
|
pub mod freelist;
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod frompyobject;
|
pub mod frompyobject;
|
||||||
pub mod ghost;
|
pub mod ghost;
|
||||||
pub(crate) mod not_send;
|
pub(crate) mod not_send;
|
||||||
pub mod panic;
|
pub mod panic;
|
||||||
#[doc(hidden)]
|
pub mod pycell;
|
||||||
pub mod pyclass;
|
pub mod pyclass;
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod pyfunction;
|
pub mod pyfunction;
|
||||||
#[doc(hidden)]
|
|
||||||
pub mod pymethods;
|
pub mod pymethods;
|
||||||
pub mod pymodule;
|
pub mod pymodule;
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
//! Externally-accessible implementation of pycell
|
||||||
|
pub use crate::pycell::impl_::{GetBorrowChecker, PyClassMutability};
|
|
@ -2,7 +2,8 @@ use crate::{
|
||||||
exceptions::{PyAttributeError, PyNotImplementedError},
|
exceptions::{PyAttributeError, PyNotImplementedError},
|
||||||
ffi,
|
ffi,
|
||||||
impl_::freelist::FreeList,
|
impl_::freelist::FreeList,
|
||||||
pycell::{GetBorrowChecker, PyCellLayout, PyClassMutability},
|
impl_::pycell::{GetBorrowChecker, PyClassMutability},
|
||||||
|
pycell::PyCellLayout,
|
||||||
pyclass_init::PyObjectInit,
|
pyclass_init::PyObjectInit,
|
||||||
type_object::PyLayout,
|
type_object::PyLayout,
|
||||||
Py, PyAny, PyCell, PyClass, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
Py, PyAny, PyCell, PyClass, PyErr, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||||
|
|
189
src/pycell.rs
189
src/pycell.rs
|
@ -200,11 +200,7 @@ use crate::exceptions::PyRuntimeError;
|
||||||
use crate::impl_::pyclass::{
|
use crate::impl_::pyclass::{
|
||||||
PyClassBaseType, PyClassDict, PyClassImpl, PyClassThreadChecker, PyClassWeakRef,
|
PyClassBaseType, PyClassDict, PyClassImpl, PyClassThreadChecker, PyClassWeakRef,
|
||||||
};
|
};
|
||||||
use crate::pyclass::PyClass;
|
use crate::pyclass::{boolean_struct::False, PyClass};
|
||||||
use crate::pyclass::{
|
|
||||||
boolean_struct::{False, True},
|
|
||||||
Frozen,
|
|
||||||
};
|
|
||||||
use crate::pyclass_init::PyClassInitializer;
|
use crate::pyclass_init::PyClassInitializer;
|
||||||
use crate::type_object::{PyLayout, PySizedLayout};
|
use crate::type_object::{PyLayout, PySizedLayout};
|
||||||
use crate::types::PyAny;
|
use crate::types::PyAny;
|
||||||
|
@ -215,175 +211,13 @@ use crate::{
|
||||||
PyTypeInfo,
|
PyTypeInfo,
|
||||||
};
|
};
|
||||||
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
|
use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
|
||||||
use std::cell::{Cell, UnsafeCell};
|
use std::cell::UnsafeCell;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
pub struct EmptySlot(());
|
pub(crate) mod impl_;
|
||||||
pub struct BorrowChecker(Cell<BorrowFlag>);
|
use impl_::{GetBorrowChecker, PyClassBorrowChecker, PyClassMutability};
|
||||||
|
|
||||||
pub trait PyClassBorrowChecker {
|
|
||||||
/// Initial value for self
|
|
||||||
fn new() -> Self;
|
|
||||||
|
|
||||||
/// Increments immutable borrow count, if possible
|
|
||||||
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
|
|
||||||
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError>;
|
|
||||||
/// Decremements mutable borrow count
|
|
||||||
fn release_borrow_mut(&self);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PyClassBorrowChecker for EmptySlot {
|
|
||||||
#[inline]
|
|
||||||
fn new() -> Self {
|
|
||||||
EmptySlot(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn release_borrow(&self) {}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn release_borrow_mut(&self) {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PyClassBorrowChecker for BorrowChecker {
|
|
||||||
#[inline]
|
|
||||||
fn new() -> Self {
|
|
||||||
Self(Cell::new(BorrowFlag::UNUSED))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
|
||||||
let flag = self.0.get();
|
|
||||||
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
|
||||||
self.0.set(flag.increment());
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(PyBorrowError { _private: () })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
|
||||||
let flag = self.0.get();
|
|
||||||
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(PyBorrowError { _private: () })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_borrow(&self) {
|
|
||||||
let flag = self.0.get();
|
|
||||||
self.0.set(flag.decrement())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
|
||||||
let flag = self.0.get();
|
|
||||||
if flag == BorrowFlag::UNUSED {
|
|
||||||
self.0.set(BorrowFlag::HAS_MUTABLE_BORROW);
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(PyBorrowMutError { _private: () })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn release_borrow_mut(&self) {
|
|
||||||
self.0.set(BorrowFlag::UNUSED)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait PyClassMutability {
|
|
||||||
// The storage for this inheritance layer. Only the first mutable class in
|
|
||||||
// an inheritance hierarchy needs to store the borrow flag.
|
|
||||||
type Storage: PyClassBorrowChecker;
|
|
||||||
// The borrow flag needed to implement this class' mutability. Empty until
|
|
||||||
// the first mutable class, at which point it is BorrowChecker and will be
|
|
||||||
// for all subclasses.
|
|
||||||
type Checker: PyClassBorrowChecker;
|
|
||||||
type ImmutableChild: PyClassMutability;
|
|
||||||
type MutableChild: PyClassMutability;
|
|
||||||
type Frozen: Frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait GetBorrowChecker<T: PyClassImpl> {
|
|
||||||
fn borrow_checker(cell: &PyCell<T>) -> &<T::PyClassMutability as PyClassMutability>::Checker;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PyClassImpl<PyClassMutability = Self>> GetBorrowChecker<T> for MutableClass {
|
|
||||||
fn borrow_checker(cell: &PyCell<T>) -> &BorrowChecker {
|
|
||||||
&cell.contents.borrow_checker
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PyClassImpl<PyClassMutability = Self>> GetBorrowChecker<T> for ImmutableClass {
|
|
||||||
fn borrow_checker(cell: &PyCell<T>) -> &EmptySlot {
|
|
||||||
&cell.contents.borrow_checker
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: PyClassImpl<PyClassMutability = Self>, M: PyClassMutability> GetBorrowChecker<T>
|
|
||||||
for ExtendsMutableAncestor<M>
|
|
||||||
where
|
|
||||||
T::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>
|
|
||||||
+ PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
|
||||||
<T::BaseType as PyClassImpl>::PyClassMutability: PyClassMutability<Checker = BorrowChecker>,
|
|
||||||
{
|
|
||||||
fn borrow_checker(cell: &PyCell<T>) -> &BorrowChecker {
|
|
||||||
<<T::BaseType as PyClassImpl>::PyClassMutability as GetBorrowChecker<T::BaseType>>::borrow_checker(&cell.ob_base)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct ImmutableClass(());
|
|
||||||
pub struct MutableClass(());
|
|
||||||
pub struct ExtendsMutableAncestor<M: PyClassMutability>(PhantomData<M>);
|
|
||||||
|
|
||||||
impl PyClassMutability for ImmutableClass {
|
|
||||||
type Storage = EmptySlot;
|
|
||||||
type Checker = EmptySlot;
|
|
||||||
type ImmutableChild = ImmutableClass;
|
|
||||||
type MutableChild = MutableClass;
|
|
||||||
type Frozen = True;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PyClassMutability for MutableClass {
|
|
||||||
type Storage = BorrowChecker;
|
|
||||||
type Checker = BorrowChecker;
|
|
||||||
type ImmutableChild = ExtendsMutableAncestor<ImmutableClass>;
|
|
||||||
type MutableChild = ExtendsMutableAncestor<MutableClass>;
|
|
||||||
type Frozen = False;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M: PyClassMutability> PyClassMutability for ExtendsMutableAncestor<M> {
|
|
||||||
type Storage = EmptySlot;
|
|
||||||
type Checker = BorrowChecker;
|
|
||||||
type ImmutableChild = ExtendsMutableAncestor<ImmutableClass>;
|
|
||||||
type MutableChild = ExtendsMutableAncestor<MutableClass>;
|
|
||||||
type Frozen = M::Frozen;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Base layout of PyCell.
|
/// Base layout of PyCell.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
@ -968,21 +802,6 @@ impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
|
||||||
pub struct BorrowFlag(usize);
|
|
||||||
|
|
||||||
impl BorrowFlag {
|
|
||||||
pub(crate) const UNUSED: BorrowFlag = BorrowFlag(0);
|
|
||||||
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
|
|
||||||
const fn increment(self) -> Self {
|
|
||||||
Self(self.0 + 1)
|
|
||||||
}
|
|
||||||
const fn decrement(self) -> Self {
|
|
||||||
Self(self.0 - 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An error type returned by [`PyCell::try_borrow`].
|
/// An error type returned by [`PyCell::try_borrow`].
|
||||||
///
|
///
|
||||||
/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
|
/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
|
||||||
|
|
|
@ -0,0 +1,387 @@
|
||||||
|
//! Crate-private implementation of pycell
|
||||||
|
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
|
use crate::impl_::pyclass::{PyClassBaseType, PyClassImpl};
|
||||||
|
use crate::PyCell;
|
||||||
|
|
||||||
|
use super::{PyBorrowError, PyBorrowMutError};
|
||||||
|
|
||||||
|
pub trait PyClassMutability {
|
||||||
|
// The storage for this inheritance layer. Only the first mutable class in
|
||||||
|
// an inheritance hierarchy needs to store the borrow flag.
|
||||||
|
type Storage: PyClassBorrowChecker;
|
||||||
|
// The borrow flag needed to implement this class' mutability. Empty until
|
||||||
|
// the first mutable class, at which point it is BorrowChecker and will be
|
||||||
|
// for all subclasses.
|
||||||
|
type Checker: PyClassBorrowChecker;
|
||||||
|
type ImmutableChild: PyClassMutability;
|
||||||
|
type MutableChild: PyClassMutability;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ImmutableClass(());
|
||||||
|
pub struct MutableClass(());
|
||||||
|
pub struct ExtendsMutableAncestor<M: PyClassMutability>(PhantomData<M>);
|
||||||
|
|
||||||
|
impl PyClassMutability for ImmutableClass {
|
||||||
|
type Storage = EmptySlot;
|
||||||
|
type Checker = EmptySlot;
|
||||||
|
type ImmutableChild = ImmutableClass;
|
||||||
|
type MutableChild = MutableClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PyClassMutability for MutableClass {
|
||||||
|
type Storage = BorrowChecker;
|
||||||
|
type Checker = BorrowChecker;
|
||||||
|
type ImmutableChild = ExtendsMutableAncestor<ImmutableClass>;
|
||||||
|
type MutableChild = ExtendsMutableAncestor<MutableClass>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M: PyClassMutability> PyClassMutability for ExtendsMutableAncestor<M> {
|
||||||
|
type Storage = EmptySlot;
|
||||||
|
type Checker = BorrowChecker;
|
||||||
|
type ImmutableChild = ExtendsMutableAncestor<ImmutableClass>;
|
||||||
|
type MutableChild = ExtendsMutableAncestor<MutableClass>;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
struct BorrowFlag(usize);
|
||||||
|
|
||||||
|
impl BorrowFlag {
|
||||||
|
pub(crate) const UNUSED: BorrowFlag = BorrowFlag(0);
|
||||||
|
const HAS_MUTABLE_BORROW: BorrowFlag = BorrowFlag(usize::max_value());
|
||||||
|
const fn increment(self) -> Self {
|
||||||
|
Self(self.0 + 1)
|
||||||
|
}
|
||||||
|
const fn decrement(self) -> Self {
|
||||||
|
Self(self.0 - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EmptySlot(());
|
||||||
|
pub struct BorrowChecker(Cell<BorrowFlag>);
|
||||||
|
|
||||||
|
pub trait PyClassBorrowChecker {
|
||||||
|
/// Initial value for self
|
||||||
|
fn new() -> Self;
|
||||||
|
|
||||||
|
/// Increments immutable borrow count, if possible
|
||||||
|
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
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError>;
|
||||||
|
/// Decremements mutable borrow count
|
||||||
|
fn release_borrow_mut(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PyClassBorrowChecker for EmptySlot {
|
||||||
|
#[inline]
|
||||||
|
fn new() -> Self {
|
||||||
|
EmptySlot(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn release_borrow(&self) {}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn release_borrow_mut(&self) {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PyClassBorrowChecker for BorrowChecker {
|
||||||
|
#[inline]
|
||||||
|
fn new() -> Self {
|
||||||
|
Self(Cell::new(BorrowFlag::UNUSED))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow(&self) -> Result<(), PyBorrowError> {
|
||||||
|
let flag = self.0.get();
|
||||||
|
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||||
|
self.0.set(flag.increment());
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow_unguarded(&self) -> Result<(), PyBorrowError> {
|
||||||
|
let flag = self.0.get();
|
||||||
|
if flag != BorrowFlag::HAS_MUTABLE_BORROW {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow(&self) {
|
||||||
|
let flag = self.0.get();
|
||||||
|
self.0.set(flag.decrement())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_borrow_mut(&self) -> Result<(), PyBorrowMutError> {
|
||||||
|
let flag = self.0.get();
|
||||||
|
if flag == BorrowFlag::UNUSED {
|
||||||
|
self.0.set(BorrowFlag::HAS_MUTABLE_BORROW);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(PyBorrowMutError { _private: () })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn release_borrow_mut(&self) {
|
||||||
|
self.0.set(BorrowFlag::UNUSED)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait GetBorrowChecker<T: PyClassImpl> {
|
||||||
|
fn borrow_checker(cell: &PyCell<T>) -> &<T::PyClassMutability as PyClassMutability>::Checker;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PyClassImpl<PyClassMutability = Self>> GetBorrowChecker<T> for MutableClass {
|
||||||
|
fn borrow_checker(cell: &PyCell<T>) -> &BorrowChecker {
|
||||||
|
&cell.contents.borrow_checker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PyClassImpl<PyClassMutability = Self>> GetBorrowChecker<T> for ImmutableClass {
|
||||||
|
fn borrow_checker(cell: &PyCell<T>) -> &EmptySlot {
|
||||||
|
&cell.contents.borrow_checker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PyClassImpl<PyClassMutability = Self>, M: PyClassMutability> GetBorrowChecker<T>
|
||||||
|
for ExtendsMutableAncestor<M>
|
||||||
|
where
|
||||||
|
T::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>
|
||||||
|
+ PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
||||||
|
<T::BaseType as PyClassImpl>::PyClassMutability: PyClassMutability<Checker = BorrowChecker>,
|
||||||
|
{
|
||||||
|
fn borrow_checker(cell: &PyCell<T>) -> &BorrowChecker {
|
||||||
|
<<T::BaseType as PyClassImpl>::PyClassMutability as GetBorrowChecker<T::BaseType>>::borrow_checker(&cell.ob_base)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[cfg(feature = "macros")]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use crate::impl_::pyclass::{PyClassBaseType, PyClassImpl};
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::pyclass::boolean_struct::{False, True};
|
||||||
|
use crate::PyClass;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", subclass)]
|
||||||
|
struct MutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableBase, subclass)]
|
||||||
|
struct MutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableBase, frozen, subclass)]
|
||||||
|
struct ImmutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableChildOfMutableBase)]
|
||||||
|
struct MutableChildOfMutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableChildOfMutableBase)]
|
||||||
|
struct MutableChildOfImmutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableChildOfMutableBase, frozen)]
|
||||||
|
struct ImmutableChildOfMutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableChildOfMutableBase, frozen)]
|
||||||
|
struct ImmutableChildOfImmutableChildOfMutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", frozen, subclass)]
|
||||||
|
struct ImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableBase, subclass)]
|
||||||
|
struct MutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableBase, frozen, subclass)]
|
||||||
|
struct ImmutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableChildOfImmutableBase)]
|
||||||
|
struct MutableChildOfMutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableChildOfImmutableBase)]
|
||||||
|
struct MutableChildOfImmutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = MutableChildOfImmutableBase, frozen)]
|
||||||
|
struct ImmutableChildOfMutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
#[pyclass(crate = "crate", extends = ImmutableChildOfImmutableBase, frozen)]
|
||||||
|
struct ImmutableChildOfImmutableChildOfImmutableBase;
|
||||||
|
|
||||||
|
fn assert_mutable<T: PyClass<Frozen = False, PyClassMutability = MutableClass>>() {}
|
||||||
|
fn assert_immutable<T: PyClass<Frozen = True, PyClassMutability = ImmutableClass>>() {}
|
||||||
|
fn assert_mutable_with_mutable_ancestor<
|
||||||
|
T: PyClass<Frozen = False, PyClassMutability = ExtendsMutableAncestor<MutableClass>>,
|
||||||
|
>()
|
||||||
|
// These horrible bounds are necessary for Rust 1.48 but not newer versions
|
||||||
|
where
|
||||||
|
<T as PyClassImpl>::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>,
|
||||||
|
<<T as PyClassImpl>::BaseType as PyClassImpl>::PyClassMutability:
|
||||||
|
PyClassMutability<Checker = BorrowChecker>,
|
||||||
|
<T as PyClassImpl>::BaseType: PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
fn assert_immutable_with_mutable_ancestor<
|
||||||
|
T: PyClass<Frozen = True, PyClassMutability = ExtendsMutableAncestor<ImmutableClass>>,
|
||||||
|
>()
|
||||||
|
// These horrible bounds are necessary for Rust 1.48 but not newer versions
|
||||||
|
where
|
||||||
|
<T as PyClassImpl>::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>,
|
||||||
|
<<T as PyClassImpl>::BaseType as PyClassImpl>::PyClassMutability:
|
||||||
|
PyClassMutability<Checker = BorrowChecker>,
|
||||||
|
<T as PyClassImpl>::BaseType: PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inherited_mutability() {
|
||||||
|
// mutable base
|
||||||
|
assert_mutable::<MutableBase>();
|
||||||
|
|
||||||
|
// children of mutable base have a mutable ancestor
|
||||||
|
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableBase>();
|
||||||
|
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableBase>();
|
||||||
|
|
||||||
|
// grandchildren of mutable base have a mutable ancestor
|
||||||
|
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableChildOfMutableBase>();
|
||||||
|
assert_mutable_with_mutable_ancestor::<MutableChildOfImmutableChildOfMutableBase>();
|
||||||
|
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableChildOfMutableBase>();
|
||||||
|
assert_immutable_with_mutable_ancestor::<ImmutableChildOfImmutableChildOfMutableBase>();
|
||||||
|
|
||||||
|
// immutable base and children
|
||||||
|
assert_immutable::<ImmutableBase>();
|
||||||
|
assert_immutable::<ImmutableChildOfImmutableBase>();
|
||||||
|
assert_immutable::<ImmutableChildOfImmutableChildOfImmutableBase>();
|
||||||
|
|
||||||
|
// mutable children of immutable at any level are simply mutable
|
||||||
|
assert_mutable::<MutableChildOfImmutableBase>();
|
||||||
|
assert_mutable::<MutableChildOfImmutableChildOfImmutableBase>();
|
||||||
|
|
||||||
|
// children of the mutable child display this property
|
||||||
|
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableChildOfImmutableBase>();
|
||||||
|
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableChildOfImmutableBase>();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_mutable_borrow_prevents_further_borrows() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let mmm = Py::new(
|
||||||
|
py,
|
||||||
|
PyClassInitializer::from(MutableBase)
|
||||||
|
.add_subclass(MutableChildOfMutableBase)
|
||||||
|
.add_subclass(MutableChildOfMutableChildOfMutableBase),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mmm_cell: &PyCell<MutableChildOfMutableChildOfMutableBase> = mmm.as_ref(py);
|
||||||
|
|
||||||
|
let mmm_refmut = mmm_cell.borrow_mut();
|
||||||
|
|
||||||
|
// Cannot take any other mutable or immutable borrows whilst the object is borrowed mutably
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_err());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_err());
|
||||||
|
|
||||||
|
// With the borrow dropped, all other borrow attempts will succeed
|
||||||
|
drop(mmm_refmut);
|
||||||
|
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_ok());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_ok());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_immutable_borrows_prevent_mutable_borrows() {
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let mmm = Py::new(
|
||||||
|
py,
|
||||||
|
PyClassInitializer::from(MutableBase)
|
||||||
|
.add_subclass(MutableChildOfMutableBase)
|
||||||
|
.add_subclass(MutableChildOfMutableChildOfMutableBase),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let mmm_cell: &PyCell<MutableChildOfMutableChildOfMutableBase> = mmm.as_ref(py);
|
||||||
|
|
||||||
|
let mmm_refmut = mmm_cell.borrow();
|
||||||
|
|
||||||
|
// Further immutable borrows are ok
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_ok());
|
||||||
|
|
||||||
|
// Further mutable borrows are not ok
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_err());
|
||||||
|
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_err());
|
||||||
|
|
||||||
|
// With the borrow dropped, all mutable borrow attempts will succeed
|
||||||
|
drop(mmm_refmut);
|
||||||
|
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell
|
||||||
|
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
||||||
|
.is_ok());
|
||||||
|
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_ok());
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,7 +4,10 @@ use crate::impl_::pyclass::{PyClassBaseType, PyClassDict, PyClassThreadChecker,
|
||||||
use crate::{ffi, PyCell, PyClass, PyErr, PyResult, Python};
|
use crate::{ffi, PyCell, PyClass, PyErr, PyResult, Python};
|
||||||
use crate::{
|
use crate::{
|
||||||
ffi::PyTypeObject,
|
ffi::PyTypeObject,
|
||||||
pycell::{PyCellContents, PyClassBorrowChecker, PyClassMutability},
|
pycell::{
|
||||||
|
impl_::{PyClassBorrowChecker, PyClassMutability},
|
||||||
|
PyCellContents,
|
||||||
|
},
|
||||||
type_object::{get_tp_alloc, PyTypeInfo},
|
type_object::{get_tp_alloc, PyTypeInfo},
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -242,7 +242,7 @@ macro_rules! pyobject_native_type_sized {
|
||||||
type BaseNativeType = $name;
|
type BaseNativeType = $name;
|
||||||
type ThreadChecker = $crate::impl_::pyclass::ThreadCheckerStub<$crate::PyObject>;
|
type ThreadChecker = $crate::impl_::pyclass::ThreadCheckerStub<$crate::PyObject>;
|
||||||
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
type Initializer = $crate::pyclass_init::PyNativeTypeInitializer<Self>;
|
||||||
type PyClassMutability = $crate::pycell::ImmutableClass;
|
type PyClassMutability = $crate::pycell::impl_::ImmutableClass;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,202 +0,0 @@
|
||||||
#![cfg(feature = "macros")]
|
|
||||||
|
|
||||||
use pyo3::impl_::pyclass::{PyClassBaseType, PyClassImpl};
|
|
||||||
use pyo3::prelude::*;
|
|
||||||
use pyo3::pycell::{
|
|
||||||
BorrowChecker, ExtendsMutableAncestor, ImmutableClass, MutableClass, PyClassMutability,
|
|
||||||
};
|
|
||||||
use pyo3::pyclass::boolean_struct::{False, True};
|
|
||||||
use pyo3::PyClass;
|
|
||||||
|
|
||||||
#[pyclass(subclass)]
|
|
||||||
struct MutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableBase, subclass)]
|
|
||||||
struct MutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableBase, frozen, subclass)]
|
|
||||||
struct ImmutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableChildOfMutableBase)]
|
|
||||||
struct MutableChildOfMutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableChildOfMutableBase)]
|
|
||||||
struct MutableChildOfImmutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableChildOfMutableBase, frozen)]
|
|
||||||
struct ImmutableChildOfMutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableChildOfMutableBase, frozen)]
|
|
||||||
struct ImmutableChildOfImmutableChildOfMutableBase;
|
|
||||||
|
|
||||||
#[pyclass(frozen, subclass)]
|
|
||||||
struct ImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableBase, subclass)]
|
|
||||||
struct MutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableBase, frozen, subclass)]
|
|
||||||
struct ImmutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableChildOfImmutableBase)]
|
|
||||||
struct MutableChildOfMutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableChildOfImmutableBase)]
|
|
||||||
struct MutableChildOfImmutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = MutableChildOfImmutableBase, frozen)]
|
|
||||||
struct ImmutableChildOfMutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
#[pyclass(extends = ImmutableChildOfImmutableBase, frozen)]
|
|
||||||
struct ImmutableChildOfImmutableChildOfImmutableBase;
|
|
||||||
|
|
||||||
fn assert_mutable<T: PyClass<Frozen = False, PyClassMutability = MutableClass>>() {}
|
|
||||||
fn assert_immutable<T: PyClass<Frozen = True, PyClassMutability = ImmutableClass>>() {}
|
|
||||||
fn assert_mutable_with_mutable_ancestor<
|
|
||||||
T: PyClass<Frozen = False, PyClassMutability = ExtendsMutableAncestor<MutableClass>>,
|
|
||||||
>()
|
|
||||||
// These horrible bounds are necessary for Rust 1.48 but not newer versions
|
|
||||||
where
|
|
||||||
<T as PyClassImpl>::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>,
|
|
||||||
<<T as PyClassImpl>::BaseType as PyClassImpl>::PyClassMutability:
|
|
||||||
PyClassMutability<Checker = BorrowChecker>,
|
|
||||||
<T as PyClassImpl>::BaseType: PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
fn assert_immutable_with_mutable_ancestor<
|
|
||||||
T: PyClass<Frozen = True, PyClassMutability = ExtendsMutableAncestor<ImmutableClass>>,
|
|
||||||
>()
|
|
||||||
// These horrible bounds are necessary for Rust 1.48 but not newer versions
|
|
||||||
where
|
|
||||||
<T as PyClassImpl>::BaseType: PyClassImpl<Layout = PyCell<T::BaseType>>,
|
|
||||||
<<T as PyClassImpl>::BaseType as PyClassImpl>::PyClassMutability:
|
|
||||||
PyClassMutability<Checker = BorrowChecker>,
|
|
||||||
<T as PyClassImpl>::BaseType: PyClassBaseType<LayoutAsBase = PyCell<T::BaseType>>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_inherited_mutability() {
|
|
||||||
// mutable base
|
|
||||||
assert_mutable::<MutableBase>();
|
|
||||||
|
|
||||||
// children of mutable base have a mutable ancestor
|
|
||||||
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableBase>();
|
|
||||||
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableBase>();
|
|
||||||
|
|
||||||
// grandchildren of mutable base have a mutable ancestor
|
|
||||||
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableChildOfMutableBase>();
|
|
||||||
assert_mutable_with_mutable_ancestor::<MutableChildOfImmutableChildOfMutableBase>();
|
|
||||||
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableChildOfMutableBase>();
|
|
||||||
assert_immutable_with_mutable_ancestor::<ImmutableChildOfImmutableChildOfMutableBase>();
|
|
||||||
|
|
||||||
// immutable base and children
|
|
||||||
assert_immutable::<ImmutableBase>();
|
|
||||||
assert_immutable::<ImmutableChildOfImmutableBase>();
|
|
||||||
assert_immutable::<ImmutableChildOfImmutableChildOfImmutableBase>();
|
|
||||||
|
|
||||||
// mutable children of immutable at any level are simply mutable
|
|
||||||
assert_mutable::<MutableChildOfImmutableBase>();
|
|
||||||
assert_mutable::<MutableChildOfImmutableChildOfImmutableBase>();
|
|
||||||
|
|
||||||
// children of the mutable child display this property
|
|
||||||
assert_mutable_with_mutable_ancestor::<MutableChildOfMutableChildOfImmutableBase>();
|
|
||||||
assert_immutable_with_mutable_ancestor::<ImmutableChildOfMutableChildOfImmutableBase>();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_mutable_borrow_prevents_further_borrows() {
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let mmm = Py::new(
|
|
||||||
py,
|
|
||||||
PyClassInitializer::from(MutableBase)
|
|
||||||
.add_subclass(MutableChildOfMutableBase)
|
|
||||||
.add_subclass(MutableChildOfMutableChildOfMutableBase),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mmm_cell: &PyCell<MutableChildOfMutableChildOfMutableBase> = mmm.as_ref(py);
|
|
||||||
|
|
||||||
let mmm_refmut = mmm_cell.borrow_mut();
|
|
||||||
|
|
||||||
// Cannot take any other mutable or immutable borrows whilst the object is borrowed mutably
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_err());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_err());
|
|
||||||
|
|
||||||
// With the borrow dropped, all other borrow attempts will succeed
|
|
||||||
drop(mmm_refmut);
|
|
||||||
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_ok());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_ok());
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_immutable_borrows_prevent_mutable_borrows() {
|
|
||||||
Python::with_gil(|py| {
|
|
||||||
let mmm = Py::new(
|
|
||||||
py,
|
|
||||||
PyClassInitializer::from(MutableBase)
|
|
||||||
.add_subclass(MutableChildOfMutableBase)
|
|
||||||
.add_subclass(MutableChildOfMutableChildOfMutableBase),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mmm_cell: &PyCell<MutableChildOfMutableChildOfMutableBase> = mmm.as_ref(py);
|
|
||||||
|
|
||||||
let mmm_refmut = mmm_cell.borrow();
|
|
||||||
|
|
||||||
// Further immutable borrows are ok
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRef<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell.extract::<PyRef<'_, MutableBase>>().is_ok());
|
|
||||||
|
|
||||||
// Further mutable borrows are not ok
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_err());
|
|
||||||
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_err());
|
|
||||||
|
|
||||||
// With the borrow dropped, all mutable borrow attempts will succeed
|
|
||||||
drop(mmm_refmut);
|
|
||||||
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell
|
|
||||||
.extract::<PyRefMut<'_, MutableChildOfMutableBase>>()
|
|
||||||
.is_ok());
|
|
||||||
assert!(mmm_cell.extract::<PyRefMut<'_, MutableBase>>().is_ok());
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +1,3 @@
|
||||||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
|
||||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
|
||||||
|
|
|
||||||
5 | #[pyclass(extends=PyDict)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
|
||||||
|
|
|
||||||
= help: the trait `PyClass` is implemented for `TestClass`
|
|
||||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
|
||||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
|
||||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
|
||||||
|
|
|
||||||
5 | #[pyclass(extends=PyDict)]
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
|
||||||
|
|
|
||||||
= help: the trait `PyClass` is implemented for `TestClass`
|
|
||||||
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
|
||||||
note: required by a bound in `PyRefMut`
|
|
||||||
--> src/pycell.rs
|
|
||||||
|
|
|
||||||
| pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
|
|
||||||
| ^^^^^^^^^^^^^^ required by this bound in `PyRefMut`
|
|
||||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
||||||
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
||||||
|
|
|
|
||||||
|
@ -37,3 +12,13 @@ note: required by a bound in `ThreadCheckerInherited`
|
||||||
| pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType>(
|
| pub struct ThreadCheckerInherited<T: PyClass + Send, U: PyClassBaseType>(
|
||||||
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
| ^^^^^^^^^^^^^^^ required by this bound in `ThreadCheckerInherited`
|
||||||
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
||||||
|
error[E0277]: the trait bound `PyDict: PyClass` is not satisfied
|
||||||
|
--> tests/ui/abi3_nativetype_inheritance.rs:5:1
|
||||||
|
|
|
||||||
|
5 | #[pyclass(extends=PyDict)]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `PyClass` is not implemented for `PyDict`
|
||||||
|
|
|
||||||
|
= help: the trait `PyClass` is implemented for `TestClass`
|
||||||
|
= note: required because of the requirements on the impl of `PyClassBaseType` for `PyDict`
|
||||||
|
= note: this error originates in the attribute macro `pyclass` (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||||
|
|
Loading…
Reference in New Issue