Implement opt-in immutable pyclasses
This commit is contained in:
parent
a28be4d9bf
commit
0fa03a67cd
|
@ -27,6 +27,7 @@ pub struct PyClassArgs {
|
|||
pub has_extends: bool,
|
||||
pub has_unsendable: bool,
|
||||
pub module: Option<syn::LitStr>,
|
||||
pub is_immutable: bool,
|
||||
}
|
||||
|
||||
impl Parse for PyClassArgs {
|
||||
|
@ -54,6 +55,7 @@ impl Default for PyClassArgs {
|
|||
is_basetype: false,
|
||||
has_extends: false,
|
||||
has_unsendable: false,
|
||||
is_immutable: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -158,6 +160,9 @@ impl PyClassArgs {
|
|||
"unsendable" => {
|
||||
self.has_unsendable = true;
|
||||
}
|
||||
"immutable" => {
|
||||
self.is_immutable = true;
|
||||
}
|
||||
_ => bail_spanned!(
|
||||
exp.path.span() => "expected one of gc/weakref/subclass/dict/unsendable"
|
||||
),
|
||||
|
@ -515,6 +520,41 @@ fn impl_class(
|
|||
let is_basetype = attr.is_basetype;
|
||||
let is_subclass = attr.has_extends;
|
||||
|
||||
let mutability = if attr.is_immutable {
|
||||
quote! {
|
||||
unsafe impl ::pyo3::pyclass::ImmutablePyClass for #cls {}
|
||||
|
||||
unsafe impl ::pyo3::class::impl_::BorrowImpl for #cls {
|
||||
fn get_borrow_flag() -> for<'r> fn(&'r ::pyo3::pycell::PyCell<Self>) -> ::pyo3::pycell::BorrowFlag
|
||||
where Self: ::pyo3::PyClass
|
||||
{
|
||||
::pyo3::pycell::impl_::get_borrow_flag_dummy
|
||||
}
|
||||
fn increment_borrow_flag() -> for<'r> fn(&'r ::pyo3::pycell::PyCell<Self>, ::pyo3::pycell::BorrowFlag)
|
||||
where Self: ::pyo3::PyClass
|
||||
{
|
||||
::pyo3::pycell::impl_::increment_borrow_flag_dummy
|
||||
}
|
||||
fn decrement_borrow_flag() -> for<'r> fn(&'r ::pyo3::pycell::PyCell<Self>, ::pyo3::pycell::BorrowFlag)
|
||||
where Self: ::pyo3::PyClass
|
||||
{
|
||||
::pyo3::pycell::impl_::decrement_borrow_flag_dummy
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
unsafe impl ::pyo3::pyclass::MutablePyClass for #cls {}
|
||||
|
||||
unsafe impl ::pyo3::class::impl_::BorrowImpl for #cls {}
|
||||
|
||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
||||
{
|
||||
type Target = ::pyo3::PyRefMut<'a, #cls>;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ok(quote! {
|
||||
unsafe impl ::pyo3::type_object::PyTypeInfo for #cls {
|
||||
type AsRefTarget = ::pyo3::PyCell<Self>;
|
||||
|
@ -538,15 +578,14 @@ fn impl_class(
|
|||
type BaseNativeType = #base_nativetype;
|
||||
}
|
||||
|
||||
#mutability
|
||||
|
||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a #cls
|
||||
{
|
||||
type Target = ::pyo3::PyRef<'a, #cls>;
|
||||
}
|
||||
|
||||
impl<'a> ::pyo3::derive_utils::ExtractExt<'a> for &'a mut #cls
|
||||
{
|
||||
type Target = ::pyo3::PyRefMut<'a, #cls>;
|
||||
}
|
||||
|
||||
|
||||
#into_pyobject
|
||||
|
||||
|
|
|
@ -9,7 +9,9 @@
|
|||
//! [typeobj docs](https://docs.python.org/3/c-api/typeobj.html)
|
||||
|
||||
use crate::callback::{HashCallbackOutput, IntoPyCallbackOutput};
|
||||
use crate::{exceptions, ffi, FromPyObject, PyAny, PyCell, PyClass, PyObject};
|
||||
use crate::{
|
||||
exceptions, ffi, pyclass::MutablePyClass, FromPyObject, PyAny, PyCell, PyClass, PyObject,
|
||||
};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Operators for the `__richcmp__` method
|
||||
|
@ -55,14 +57,14 @@ pub trait PyObjectProtocol<'p>: PyClass {
|
|||
|
||||
fn __setattr__(&'p mut self, name: Self::Name, value: Self::Value) -> Self::Result
|
||||
where
|
||||
Self: PyObjectSetAttrProtocol<'p>,
|
||||
Self: PyObjectSetAttrProtocol<'p> + MutablePyClass,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn __delattr__(&'p mut self, name: Self::Name) -> Self::Result
|
||||
where
|
||||
Self: PyObjectDelAttrProtocol<'p>,
|
||||
Self: PyObjectDelAttrProtocol<'p> + MutablePyClass,
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -128,12 +130,12 @@ pub trait PyObjectGetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
|||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
pub trait PyObjectSetAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> {
|
||||
pub trait PyObjectDelAttrProtocol<'p>: PyObjectProtocol<'p> + MutablePyClass {
|
||||
type Name: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
//! For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
//! c-api
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{ffi, PyCell, PyClass, PyRefMut};
|
||||
use crate::{ffi, pyclass::MutablePyClass, PyCell, PyRefMut};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -13,7 +13,7 @@ use std::os::raw::c_int;
|
|||
/// For more information check [buffer protocol](https://docs.python.org/3/c-api/buffer.html)
|
||||
/// c-api.
|
||||
#[allow(unused_variables)]
|
||||
pub trait PyBufferProtocol<'p>: PyClass {
|
||||
pub trait PyBufferProtocol<'p>: MutablePyClass {
|
||||
// No default implementations so that implementors of this trait provide both methods.
|
||||
|
||||
fn bf_getbuffer(slf: PyRefMut<Self>, view: *mut ffi::Py_buffer, flags: c_int) -> Self::Result
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
//! Python GC support
|
||||
|
||||
use crate::{ffi, AsPyPointer, PyCell, PyClass, Python};
|
||||
use crate::{ffi, pyclass::MutablePyClass, AsPyPointer, PyCell, Python};
|
||||
use std::os::raw::{c_int, c_void};
|
||||
|
||||
#[repr(transparent)]
|
||||
|
@ -10,7 +10,7 @@ pub struct PyTraverseError(c_int);
|
|||
|
||||
/// GC support
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyGCProtocol<'p>: PyClass {
|
||||
pub trait PyGCProtocol<'p>: MutablePyClass {
|
||||
fn __traverse__(&'p self, visit: PyVisit) -> Result<(), PyTraverseError>;
|
||||
fn __clear__(&'p mut self);
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::{
|
|||
exceptions::{PyAttributeError, PyNotImplementedError},
|
||||
ffi,
|
||||
impl_::freelist::FreeList,
|
||||
pycell::PyCellLayout,
|
||||
pycell::{self, PyCellLayout},
|
||||
pyclass_init::PyObjectInit,
|
||||
type_object::{PyLayout, PyTypeObject},
|
||||
PyClass, PyMethodDefType, PyNativeType, PyResult, PyTypeInfo, Python,
|
||||
|
@ -39,7 +39,7 @@ impl<T> Copy for PyClassImplCollector<T> {}
|
|||
///
|
||||
/// 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 + BorrowImpl {
|
||||
/// Class doc string
|
||||
const DOC: &'static str = "\0";
|
||||
|
||||
|
@ -83,6 +83,27 @@ pub trait PyClassImpl: Sized {
|
|||
}
|
||||
}
|
||||
|
||||
pub unsafe trait BorrowImpl {
|
||||
fn get_borrow_flag() -> for<'r> fn(&'r pycell::PyCell<Self>) -> pycell::BorrowFlag
|
||||
where
|
||||
Self: PyClass,
|
||||
{
|
||||
pycell::impl_::get_borrow_flag
|
||||
}
|
||||
fn increment_borrow_flag() -> for<'r> fn(&'r pycell::PyCell<Self>, pycell::BorrowFlag)
|
||||
where
|
||||
Self: PyClass,
|
||||
{
|
||||
pycell::impl_::increment_borrow_flag
|
||||
}
|
||||
fn decrement_borrow_flag() -> for<'r> fn(&'r pycell::PyCell<Self>, pycell::BorrowFlag)
|
||||
where
|
||||
Self: PyClass,
|
||||
{
|
||||
pycell::impl_::decrement_borrow_flag
|
||||
}
|
||||
}
|
||||
|
||||
// Traits describing known special methods.
|
||||
|
||||
pub trait PyClassNewImpl<T> {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! Trait and support implementation for implementing mapping support
|
||||
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::{FromPyObject, PyClass, PyObject};
|
||||
use crate::{pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Mapping interface
|
||||
#[allow(unused_variables)]
|
||||
|
@ -61,13 +61,13 @@ pub trait PyMappingGetItemProtocol<'p>: PyMappingProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||
pub trait PyMappingSetItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> {
|
||||
pub trait PyMappingDelItemProtocol<'p>: PyMappingProtocol<'p> + MutablePyClass {
|
||||
type Key: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//! Trait and support implementation for implementing number protocol
|
||||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::err::PyErr;
|
||||
use crate::{ffi, FromPyObject, PyClass, PyObject};
|
||||
use crate::{ffi, pyclass::MutablePyClass, FromPyObject, PyClass, PyObject};
|
||||
|
||||
/// Number interface
|
||||
#[allow(unused_variables)]
|
||||
|
@ -481,74 +481,74 @@ pub trait PyNumberROrProtocol<'p>: PyNumberProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIAddProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberISubProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIMulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIMatmulProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberITruedivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIFloordivProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIModProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIDivmodProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIPowProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberILShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
#[allow(clippy::upper_case_acronyms)]
|
||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIRShiftProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIAndProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIXorProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> {
|
||||
pub trait PyNumberIOrProtocol<'p>: PyNumberProtocol<'p> + MutablePyClass {
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
use crate::callback::IntoPyCallbackOutput;
|
||||
use crate::conversion::{FromPyObject, IntoPy};
|
||||
use crate::err::PyErr;
|
||||
use crate::{exceptions, ffi, PyAny, PyCell, PyClass, PyObject};
|
||||
use crate::{exceptions, ffi, pyclass::MutablePyClass, PyAny, PyCell, PyClass, PyObject};
|
||||
use std::os::raw::c_int;
|
||||
|
||||
/// Sequence interface
|
||||
|
@ -88,13 +88,13 @@ pub trait PySequenceGetItemProtocol<'p>: PySequenceProtocol<'p> {
|
|||
type Result: IntoPyCallbackOutput<PyObject>;
|
||||
}
|
||||
|
||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||
pub trait PySequenceSetItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Value: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> {
|
||||
pub trait PySequenceDelItemProtocol<'p>: PySequenceProtocol<'p> + MutablePyClass {
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<()>;
|
||||
}
|
||||
|
@ -115,14 +115,14 @@ pub trait PySequenceRepeatProtocol<'p>: PySequenceProtocol<'p> {
|
|||
}
|
||||
|
||||
pub trait PySequenceInplaceConcatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass
|
||||
{
|
||||
type Other: FromPyObject<'p>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
}
|
||||
|
||||
pub trait PySequenceInplaceRepeatProtocol<'p>:
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + 'p
|
||||
PySequenceProtocol<'p> + IntoPy<PyObject> + MutablePyClass + 'p
|
||||
{
|
||||
type Index: FromPyObject<'p> + From<isize>;
|
||||
type Result: IntoPyCallbackOutput<Self>;
|
||||
|
|
|
@ -5,7 +5,8 @@ use crate::err::{self, PyDowncastError, PyResult};
|
|||
use crate::type_object::PyTypeInfo;
|
||||
use crate::types::PyTuple;
|
||||
use crate::{
|
||||
ffi, gil, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef, PyRefMut, Python,
|
||||
ffi, gil, pyclass::MutablePyClass, Py, PyAny, PyCell, PyClass, PyNativeType, PyObject, PyRef,
|
||||
PyRefMut, Python,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
|
@ -329,7 +330,7 @@ where
|
|||
|
||||
impl<'a, T> FromPyObject<'a> for PyRefMut<'a, T>
|
||||
where
|
||||
T: PyClass,
|
||||
T: MutablePyClass,
|
||||
{
|
||||
fn extract(obj: &'a PyAny) -> PyResult<Self> {
|
||||
let cell: &PyCell<T> = PyTryFrom::try_from(obj)?;
|
||||
|
|
|
@ -5,8 +5,8 @@ use crate::gil;
|
|||
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
|
||||
use crate::types::{PyDict, PyTuple};
|
||||
use crate::{
|
||||
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
|
||||
PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
|
||||
ffi, pyclass::MutablePyClass, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass,
|
||||
PyClassInitializer, PyRef, PyRefMut, PyTypeInfo, Python, ToPyObject,
|
||||
};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem;
|
||||
|
@ -423,7 +423,10 @@ where
|
|||
/// # Panics
|
||||
/// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
|
||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||
pub fn borrow_mut<'py>(&'py self, py: Python<'py>) -> PyRefMut<'py, T> {
|
||||
pub fn borrow_mut<'py>(&'py self, py: Python<'py>) -> PyRefMut<'py, T>
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
self.as_ref(py).borrow_mut()
|
||||
}
|
||||
|
||||
|
@ -450,7 +453,10 @@ where
|
|||
pub fn try_borrow_mut<'py>(
|
||||
&'py self,
|
||||
py: Python<'py>,
|
||||
) -> Result<PyRefMut<'py, T>, PyBorrowMutError> {
|
||||
) -> Result<PyRefMut<'py, T>, PyBorrowMutError>
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
self.as_ref(py).try_borrow_mut()
|
||||
}
|
||||
}
|
||||
|
@ -802,7 +808,7 @@ where
|
|||
|
||||
impl<'a, T> std::convert::From<PyRefMut<'a, T>> for Py<T>
|
||||
where
|
||||
T: PyClass,
|
||||
T: MutablePyClass,
|
||||
{
|
||||
fn from(pyref: PyRefMut<'a, T>) -> Self {
|
||||
unsafe { Py::from_borrowed_ptr(pyref.py(), pyref.as_ptr()) }
|
||||
|
|
109
src/pycell.rs
109
src/pycell.rs
|
@ -175,7 +175,7 @@
|
|||
//! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell<T> and the Interior Mutability Pattern - The Rust Programming Language"
|
||||
|
||||
use crate::exceptions::PyRuntimeError;
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::pyclass::{ImmutablePyClass, MutablePyClass, PyClass};
|
||||
use crate::pyclass_init::PyClassInitializer;
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
use crate::type_object::{PyLayout, PySizedLayout};
|
||||
|
@ -362,7 +362,10 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// Panics if the value is currently borrowed. For a non-panicking variant, use
|
||||
/// [`try_borrow_mut`](#method.try_borrow_mut).
|
||||
pub fn borrow_mut(&self) -> PyRefMut<'_, T> {
|
||||
pub fn borrow_mut(&self) -> PyRefMut<'_, T>
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
self.try_borrow_mut().expect("Already borrowed")
|
||||
}
|
||||
|
||||
|
@ -392,11 +395,11 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// });
|
||||
/// ```
|
||||
pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
|
||||
let flag = self.get_borrow_flag();
|
||||
let flag = crate::class::impl_::BorrowImpl::get_borrow_flag()(self);
|
||||
if flag == BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
self.set_borrow_flag(flag.increment());
|
||||
crate::class::impl_::BorrowImpl::increment_borrow_flag()(self, flag);
|
||||
Ok(PyRef { inner: self })
|
||||
}
|
||||
}
|
||||
|
@ -422,7 +425,10 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// assert!(c.try_borrow_mut().is_ok());
|
||||
/// });
|
||||
/// ```
|
||||
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError> {
|
||||
pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError>
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
if self.get_borrow_flag() != BorrowFlag::UNUSED {
|
||||
Err(PyBorrowMutError { _private: () })
|
||||
} else {
|
||||
|
@ -461,7 +467,9 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// });
|
||||
/// ```
|
||||
pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
|
||||
if self.get_borrow_flag() == BorrowFlag::HAS_MUTABLE_BORROW {
|
||||
if crate::class::impl_::BorrowImpl::get_borrow_flag()(self)
|
||||
== BorrowFlag::HAS_MUTABLE_BORROW
|
||||
{
|
||||
Err(PyBorrowError { _private: () })
|
||||
} else {
|
||||
Ok(&*self.contents.value.get())
|
||||
|
@ -474,7 +482,10 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
#[inline]
|
||||
pub fn replace(&self, t: T) -> T {
|
||||
pub fn replace(&self, t: T) -> T
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
std::mem::replace(&mut *self.borrow_mut(), t)
|
||||
}
|
||||
|
||||
|
@ -483,7 +494,10 @@ impl<T: PyClass> PyCell<T> {
|
|||
/// # Panics
|
||||
///
|
||||
/// Panics if the value is currently borrowed.
|
||||
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T {
|
||||
pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
let mut_borrow = &mut *self.borrow_mut();
|
||||
let replacement = f(mut_borrow);
|
||||
std::mem::replace(mut_borrow, replacement)
|
||||
|
@ -495,7 +509,10 @@ impl<T: PyClass> PyCell<T> {
|
|||
///
|
||||
/// Panics if the value in either `PyCell` is currently borrowed.
|
||||
#[inline]
|
||||
pub fn swap(&self, other: &Self) {
|
||||
pub fn swap(&self, other: &Self)
|
||||
where
|
||||
T: MutablePyClass,
|
||||
{
|
||||
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
|
||||
}
|
||||
|
||||
|
@ -504,6 +521,42 @@ impl<T: PyClass> PyCell<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod impl_ {
|
||||
use super::*;
|
||||
|
||||
#[inline]
|
||||
pub fn get_borrow_flag<T: PyClass>(slf: &PyCell<T>) -> BorrowFlag {
|
||||
PyCellLayout::get_borrow_flag(slf)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn get_borrow_flag_dummy<T: ImmutablePyClass>(_slf: &PyCell<T>) -> BorrowFlag {
|
||||
debug_assert_eq!(PyCellLayout::get_borrow_flag(_slf), BorrowFlag::UNUSED);
|
||||
BorrowFlag::UNUSED
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn increment_borrow_flag<T: PyClass>(slf: &PyCell<T>, flag: BorrowFlag) {
|
||||
PyCellLayout::set_borrow_flag(slf, flag.increment());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn increment_borrow_flag_dummy<T: ImmutablePyClass>(_slf: &PyCell<T>, _flag: BorrowFlag) {
|
||||
debug_assert_eq!(PyCellLayout::get_borrow_flag(_slf), BorrowFlag::UNUSED);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decrement_borrow_flag<T: PyClass>(slf: &PyCell<T>, flag: BorrowFlag) {
|
||||
PyCellLayout::set_borrow_flag(slf, flag.decrement());
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decrement_borrow_flag_dummy<T: ImmutablePyClass>(_slf: &PyCell<T>, _flag: BorrowFlag) {
|
||||
debug_assert_eq!(PyCellLayout::get_borrow_flag(_slf), BorrowFlag::UNUSED);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: PyClass> PyLayout<T> for PyCell<T> {}
|
||||
impl<T: PyClass> PySizedLayout<T> for PyCell<T> {}
|
||||
|
||||
|
@ -687,8 +740,8 @@ impl<'p, T: PyClass> Deref for PyRef<'p, T> {
|
|||
|
||||
impl<'p, T: PyClass> Drop for PyRef<'p, T> {
|
||||
fn drop(&mut self) {
|
||||
let flag = self.inner.get_borrow_flag();
|
||||
self.inner.set_borrow_flag(flag.decrement())
|
||||
let flag = crate::class::impl_::BorrowImpl::get_borrow_flag()(self.inner);
|
||||
crate::class::impl_::BorrowImpl::decrement_borrow_flag()(self.inner, flag);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -720,11 +773,11 @@ impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
|
|||
/// A wrapper type for a mutably borrowed value from a[`PyCell`]`<T>`.
|
||||
///
|
||||
/// See the [module-level documentation](self) for more information.
|
||||
pub struct PyRefMut<'p, T: PyClass> {
|
||||
pub struct PyRefMut<'p, T: MutablePyClass> {
|
||||
inner: &'p PyCell<T>,
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> PyRefMut<'p, T> {
|
||||
impl<'p, T: MutablePyClass> PyRefMut<'p, T> {
|
||||
/// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
|
||||
pub fn py(&self) -> Python {
|
||||
unsafe { Python::assume_gil_acquired() }
|
||||
|
@ -733,8 +786,8 @@ impl<'p, T: PyClass> PyRefMut<'p, T> {
|
|||
|
||||
impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
fn as_ref(&self) -> &T::BaseType {
|
||||
unsafe { &*self.inner.ob_base.get_ptr() }
|
||||
|
@ -743,8 +796,8 @@ where
|
|||
|
||||
impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
fn as_mut(&mut self) -> &mut T::BaseType {
|
||||
unsafe { &mut *self.inner.ob_base.get_ptr() }
|
||||
|
@ -753,8 +806,8 @@ where
|
|||
|
||||
impl<'p, T, U> PyRefMut<'p, T>
|
||||
where
|
||||
T: PyClass<BaseType = U>,
|
||||
U: PyClass,
|
||||
T: PyClass<BaseType = U> + MutablePyClass,
|
||||
U: MutablePyClass,
|
||||
{
|
||||
/// Gets a `PyRef<T::BaseType>`.
|
||||
///
|
||||
|
@ -768,7 +821,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
||||
impl<'p, T: MutablePyClass> Deref for PyRefMut<'p, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
|
@ -777,46 +830,46 @@ impl<'p, T: PyClass> Deref for PyRefMut<'p, T> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> DerefMut for PyRefMut<'p, T> {
|
||||
impl<'p, T: MutablePyClass> DerefMut for PyRefMut<'p, T> {
|
||||
#[inline]
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.inner.get_ptr() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p, T: PyClass> Drop for PyRefMut<'p, T> {
|
||||
impl<'p, T: MutablePyClass> Drop for PyRefMut<'p, T> {
|
||||
fn drop(&mut self) {
|
||||
self.inner.set_borrow_flag(BorrowFlag::UNUSED)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
||||
impl<T: MutablePyClass> IntoPy<PyObject> for PyRefMut<'_, T> {
|
||||
fn into_py(self, py: Python) -> PyObject {
|
||||
unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PyClass> AsPyPointer for PyRefMut<'a, T> {
|
||||
impl<'a, T: MutablePyClass> AsPyPointer for PyRefMut<'a, T> {
|
||||
fn as_ptr(&self) -> *mut ffi::PyObject {
|
||||
self.inner.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRefMut<'a, T> {
|
||||
impl<'a, T: MutablePyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRefMut<'a, T> {
|
||||
type Error = PyBorrowMutError;
|
||||
fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
|
||||
cell.try_borrow_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||
impl<T: MutablePyClass + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Debug::fmt(&*(self.deref()), f)
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct BorrowFlag(usize);
|
||||
|
||||
impl BorrowFlag {
|
||||
|
@ -884,6 +937,7 @@ impl From<PyBorrowMutError> for PyErr {
|
|||
pub trait PyCellLayout<T>: PyLayout<T> {
|
||||
fn get_borrow_flag(&self) -> BorrowFlag;
|
||||
fn set_borrow_flag(&self, flag: BorrowFlag);
|
||||
|
||||
/// Implementation of tp_dealloc.
|
||||
/// # Safety
|
||||
/// - slf must be a valid pointer to an instance of a T or a subclass.
|
||||
|
@ -902,6 +956,7 @@ where
|
|||
fn set_borrow_flag(&self, flag: BorrowFlag) {
|
||||
self.borrow_flag.set(flag)
|
||||
}
|
||||
|
||||
unsafe fn tp_dealloc(slf: *mut ffi::PyObject, py: Python) {
|
||||
// For `#[pyclass]` types which inherit from PyAny, we can just call tp_free
|
||||
if T::type_object_raw(py) == &mut PyBaseObject_Type {
|
||||
|
|
|
@ -29,6 +29,9 @@ pub trait PyClass:
|
|||
type BaseNativeType: PyTypeInfo + PyNativeType;
|
||||
}
|
||||
|
||||
pub unsafe trait MutablePyClass: PyClass {}
|
||||
pub unsafe trait ImmutablePyClass: PyClass {}
|
||||
|
||||
/// For collecting slot items.
|
||||
#[derive(Default)]
|
||||
struct TypeSlots(Vec<ffi::PyType_Slot>);
|
||||
|
|
|
@ -24,6 +24,7 @@ fn _test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||
t.compile_fail("tests/ui/invalid_argument_attributes.rs");
|
||||
t.compile_fail("tests/ui/reject_generics.rs");
|
||||
t.compile_fail("tests/ui/invalid_immutable_pyclass_borrow.rs");
|
||||
|
||||
tests_rust_1_48(&t);
|
||||
tests_rust_1_49(&t);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
use pyo3::prelude::*;
|
||||
|
||||
#[pyclass(immutable)]
|
||||
pub struct Foo {
|
||||
#[pyo3(get)]
|
||||
field: u32,
|
||||
}
|
||||
|
||||
fn borrow_mut_fails(foo: Py<Foo>, py: Python){
|
||||
let borrow = foo.as_ref(py).borrow_mut();
|
||||
}
|
||||
|
||||
fn main(){}
|
|
@ -0,0 +1,5 @@
|
|||
error[E0277]: the trait bound `Foo: MutablePyClass` is not satisfied
|
||||
--> tests/ui/invalid_immutable_pyclass_borrow.rs:10:33
|
||||
|
|
||||
10 | let borrow = foo.as_ref(py).borrow_mut();
|
||||
| ^^^^^^^^^^ the trait `MutablePyClass` is not implemented for `Foo`
|
|
@ -11,8 +11,8 @@ note: required because it appears within the type `NotThreadSafe`
|
|||
5 | struct NotThreadSafe {
|
||||
| ^^^^^^^^^^^^^
|
||||
note: required by a bound in `ThreadCheckerStub`
|
||||
--> src/class/impl_.rs:710:33
|
||||
--> src/class/impl_.rs:731:33
|
||||
|
|
||||
710 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
731 | pub struct ThreadCheckerStub<T: Send>(PhantomData<T>);
|
||||
| ^^^^ required by this bound in `ThreadCheckerStub`
|
||||
= 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