Skip to main content

pyo3/
pycell.rs

1//! PyO3's interior mutability primitive.
2//!
3//! Rust has strict aliasing rules - you can either have any number of immutable (shared) references or one mutable
4//! reference. Python's ownership model is the complete opposite of that - any Python object
5//! can be referenced any number of times, and mutation is allowed from any reference.
6//!
7//! PyO3 deals with these differences by employing the [Interior Mutability]
8//! pattern. This requires that PyO3 enforces the borrowing rules and it has two mechanisms for
9//! doing so:
10//! - Statically it can enforce thread-safe access with the [`Python<'py>`](crate::Python) token.
11//!   All Rust code holding that token, or anything derived from it, can assume that they have
12//!   safe access to the Python interpreter's state. For this reason all the native Python objects
13//!   can be mutated through shared references.
14//! - However, methods and functions in Rust usually *do* need `&mut` references. While PyO3 can
15//!   use the [`Python<'py>`](crate::Python) token to guarantee thread-safe access to them, it cannot
16//!   statically guarantee uniqueness of `&mut` references. As such those references have to be tracked
17//!   dynamically at runtime, using `PyCell` and the other types defined in this module. This works
18//!   similar to std's [`RefCell`](std::cell::RefCell) type.
19//!
20//! # When *not* to use PyCell
21//!
22//! Usually you can use `&mut` references as method and function receivers and arguments, and you
23//! won't need to use `PyCell` directly:
24//!
25//! ```rust,no_run
26//! use pyo3::prelude::*;
27//!
28//! #[pyclass]
29//! struct Number {
30//!     inner: u32,
31//! }
32//!
33//! #[pymethods]
34//! impl Number {
35//!     fn increment(&mut self) {
36//!         self.inner += 1;
37//!     }
38//! }
39//! ```
40//!
41//! The [`#[pymethods]`](crate::pymethods) proc macro will generate this wrapper function (and more),
42//! using `PyCell` under the hood:
43//!
44//! ```rust,ignore
45//! # use pyo3::prelude::*;
46//! # #[pyclass]
47//! # struct Number {
48//! #    inner: u32,
49//! # }
50//! #
51//! # #[pymethods]
52//! # impl Number {
53//! #    fn increment(&mut self) {
54//! #        self.inner += 1;
55//! #    }
56//! # }
57//! #
58//! // The function which is exported to Python looks roughly like the following
59//! unsafe extern "C" fn __pymethod_increment__(
60//!     _slf: *mut pyo3::ffi::PyObject,
61//!     _args: *mut pyo3::ffi::PyObject,
62//! ) -> *mut pyo3::ffi::PyObject {
63//!     use :: pyo3 as _pyo3;
64//!     _pyo3::impl_::trampoline::noargs(_slf, _args, |py, _slf| {
65//! #       #[allow(deprecated)]
66//!         let _cell = py
67//!             .from_borrowed_ptr::<_pyo3::PyAny>(_slf)
68//!             .cast::<_pyo3::PyCell<Number>>()?;
69//!         let mut _ref = _cell.try_borrow_mut()?;
70//!         let _slf: &mut Number = &mut *_ref;
71//!         _pyo3::impl_::callback::convert(py, Number::increment(_slf))
72//!     })
73//! }
74//! ```
75//!
76//! # When to use PyCell
77//! ## Using pyclasses from Rust
78//!
79//! However, we *do* need `PyCell` if we want to call its methods from Rust:
80//! ```rust
81//! # use pyo3::prelude::*;
82//! #
83//! # #[pyclass]
84//! # struct Number {
85//! #     inner: u32,
86//! # }
87//! #
88//! # #[pymethods]
89//! # impl Number {
90//! #     fn increment(&mut self) {
91//! #         self.inner += 1;
92//! #     }
93//! # }
94//! # fn main() -> PyResult<()> {
95//! Python::attach(|py| {
96//!     let n = Py::new(py, Number { inner: 0 })?;
97//!
98//!     // We borrow the guard and then dereference
99//!     // it to get a mutable reference to Number
100//!     let mut guard: PyRefMut<'_, Number> = n.bind(py).borrow_mut();
101//!     let n_mutable: &mut Number = &mut *guard;
102//!
103//!     n_mutable.increment();
104//!
105//!     // To avoid panics we must dispose of the
106//!     // `PyRefMut` before borrowing again.
107//!     drop(guard);
108//!
109//!     let n_immutable: &Number = &n.bind(py).borrow();
110//!     assert_eq!(n_immutable.inner, 1);
111//!
112//!     Ok(())
113//! })
114//! # }
115//! ```
116//! ## Dealing with possibly overlapping mutable references
117//!
118//! It is also necessary to use `PyCell` if you can receive mutable arguments that may overlap.
119//! Suppose the following function that swaps the values of two `Number`s:
120//! ```
121//! # use pyo3::prelude::*;
122//! # #[pyclass]
123//! # pub struct Number {
124//! #     inner: u32,
125//! # }
126//! #[pyfunction]
127//! fn swap_numbers(a: &mut Number, b: &mut Number) {
128//!     std::mem::swap(&mut a.inner, &mut b.inner);
129//! }
130//! # fn main() {
131//! #     Python::attach(|py| {
132//! #         let n = Py::new(py, Number{inner: 35}).unwrap();
133//! #         let n2 = n.clone_ref(py);
134//! #         assert!(n.is(&n2));
135//! #         let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
136//! #         fun.call1((n, n2)).expect_err("Managed to create overlapping mutable references. Note: this is undefined behaviour.");
137//! #     });
138//! # }
139//! ```
140//! When users pass in the same `Number` as both arguments, one of the mutable borrows will
141//! fail and raise a `RuntimeError`:
142//! ```text
143//! >>> a = Number()
144//! >>> swap_numbers(a, a)
145//! Traceback (most recent call last):
146//!   File "<stdin>", line 1, in <module>
147//!   RuntimeError: Already borrowed
148//! ```
149//!
150//! It is better to write that function like this:
151//! ```rust,ignore
152//! # #![allow(deprecated)]
153//! # use pyo3::prelude::*;
154//! # #[pyclass]
155//! # pub struct Number {
156//! #     inner: u32,
157//! # }
158//! #[pyfunction]
159//! fn swap_numbers(a: &PyCell<Number>, b: &PyCell<Number>) {
160//!     // Check that the pointers are unequal
161//!     if !a.is(b) {
162//!         std::mem::swap(&mut a.borrow_mut().inner, &mut b.borrow_mut().inner);
163//!     } else {
164//!         // Do nothing - they are the same object, so don't need swapping.
165//!     }
166//! }
167//! # fn main() {
168//! #     // With duplicate numbers
169//! #     Python::attach(|py| {
170//! #         let n = Py::new(py, Number{inner: 35}).unwrap();
171//! #         let n2 = n.clone_ref(py);
172//! #         assert!(n.is(&n2));
173//! #         let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
174//! #         fun.call1((n, n2)).unwrap();
175//! #     });
176//! #
177//! #     // With two different numbers
178//! #     Python::attach(|py| {
179//! #         let n = Py::new(py, Number{inner: 35}).unwrap();
180//! #         let n2 = Py::new(py, Number{inner: 42}).unwrap();
181//! #         assert!(!n.is(&n2));
182//! #         let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
183//! #         fun.call1((&n, &n2)).unwrap();
184//! #         let n: u32 = n.borrow(py).inner;
185//! #         let n2: u32 = n2.borrow(py).inner;
186//! #         assert_eq!(n, 42);
187//! #         assert_eq!(n2, 35);
188//! #     });
189//! # }
190//! ```
191//! See the [guide] for more information.
192//!
193//! [guide]: https://pyo3.rs/latest/class.html#pycell-and-interior-mutability "PyCell and interior mutability"
194//! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell<T> and the Interior Mutability Pattern - The Rust Programming Language"
195
196use crate::conversion::IntoPyObject;
197use crate::exceptions::PyRuntimeError;
198use crate::ffi_ptr_ext::FfiPtrExt;
199use crate::pyclass::{boolean_struct::False, PyClass};
200use crate::{ffi, Borrowed, Bound, PyErr, Python};
201use std::convert::Infallible;
202use std::fmt;
203use std::mem::ManuallyDrop;
204use std::ops::{Deref, DerefMut};
205use std::ptr::NonNull;
206
207pub(crate) mod impl_;
208#[cfg(feature = "experimental-inspect")]
209use crate::inspect::PyStaticExpr;
210use impl_::{PyClassBorrowChecker, PyClassObjectBaseLayout, PyClassObjectLayout};
211
212/// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`].
213///
214/// See the [`Bound`] documentation for more information.
215///
216/// # Examples
217///
218/// You can use [`PyRef`] as an alternative to a `&self` receiver when
219/// - you need to access the pointer of the [`Bound`], or
220/// - you want to get a super class.
221/// ```
222/// # use pyo3::prelude::*;
223/// #[pyclass(subclass)]
224/// struct Parent {
225///     basename: &'static str,
226/// }
227///
228/// #[pyclass(extends=Parent)]
229/// struct Child {
230///     name: &'static str,
231///  }
232///
233/// #[pymethods]
234/// impl Child {
235///     #[new]
236///     fn new() -> (Self, Parent) {
237///         (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
238///     }
239///
240///     fn format(slf: PyRef<'_, Self>) -> String {
241///         // We can get *mut ffi::PyObject from PyRef
242///         let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
243///         // We can get &Self::BaseType by as_ref
244///         let basename = slf.as_ref().basename;
245///         format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
246///     }
247/// }
248/// # Python::attach(|py| {
249/// #     let sub = Py::new(py, Child::new()).unwrap();
250/// #     pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()");
251/// # });
252/// ```
253///
254/// See the [module-level documentation](self) for more information.
255#[repr(transparent)]
256pub struct PyRef<'p, T: PyClass> {
257    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
258    // store `Borrowed` here instead, avoiding reference counting overhead.
259    inner: Bound<'p, T>,
260}
261
262impl<'p, T: PyClass> PyRef<'p, T> {
263    /// Returns a `Python` token that is bound to the lifetime of the `PyRef`.
264    pub fn py(&self) -> Python<'p> {
265        self.inner.py()
266    }
267}
268
269impl<T, U> AsRef<U> for PyRef<'_, T>
270where
271    T: PyClass<BaseType = U>,
272    U: PyClass,
273{
274    fn as_ref(&self) -> &T::BaseType {
275        self.as_super()
276    }
277}
278
279impl<'py, T: PyClass> PyRef<'py, T> {
280    /// Returns the raw FFI pointer represented by self.
281    ///
282    /// # Safety
283    ///
284    /// Callers are responsible for ensuring that the pointer does not outlive self.
285    ///
286    /// The reference is borrowed; callers should not decrease the reference count
287    /// when they are finished with the pointer.
288    #[inline]
289    pub fn as_ptr(&self) -> *mut ffi::PyObject {
290        self.inner.as_ptr()
291    }
292
293    /// Returns an owned raw FFI pointer represented by self.
294    ///
295    /// # Safety
296    ///
297    /// The reference is owned; when finished the caller should either transfer ownership
298    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
299    #[inline]
300    pub fn into_ptr(self) -> *mut ffi::PyObject {
301        self.inner.clone().into_ptr()
302    }
303
304    #[track_caller]
305    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
306        Self::try_borrow(obj).expect("Already mutably borrowed")
307    }
308
309    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowError> {
310        let cell = obj.get_class_object();
311        cell.ensure_threadsafe();
312        cell.borrow_checker()
313            .try_borrow()
314            .map(|_| Self { inner: obj.clone() })
315    }
316}
317
318impl<'p, T> PyRef<'p, T>
319where
320    T: PyClass,
321    T::BaseType: PyClass,
322{
323    /// Gets a `PyRef<T::BaseType>`.
324    ///
325    /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be
326    /// used to get the base of `T::BaseType`.
327    ///
328    /// But with the help of this method, you can get hold of instances of the
329    /// super-superclass when needed.
330    ///
331    /// # Examples
332    /// ```
333    /// # use pyo3::prelude::*;
334    /// #[pyclass(subclass)]
335    /// struct Base1 {
336    ///     name1: &'static str,
337    /// }
338    ///
339    /// #[pyclass(extends=Base1, subclass)]
340    /// struct Base2 {
341    ///     name2: &'static str,
342    /// }
343    ///
344    /// #[pyclass(extends=Base2)]
345    /// struct Sub {
346    ///     name3: &'static str,
347    /// }
348    ///
349    /// #[pymethods]
350    /// impl Sub {
351    ///     #[new]
352    ///     fn new() -> PyClassInitializer<Self> {
353    ///         PyClassInitializer::from(Base1 { name1: "base1" })
354    ///             .add_subclass(Base2 { name2: "base2" })
355    ///             .add_subclass(Self { name3: "sub" })
356    ///     }
357    ///     fn name(slf: PyRef<'_, Self>) -> String {
358    ///         let subname = slf.name3;
359    ///         let super_ = slf.into_super();
360    ///         format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
361    ///     }
362    /// }
363    /// # Python::attach(|py| {
364    /// #     let sub = Py::new(py, Sub::new()).unwrap();
365    /// #     pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
366    /// # });
367    /// ```
368    pub fn into_super(self) -> PyRef<'p, T::BaseType> {
369        let py = self.py();
370        let t_not_frozen = !<T::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;
371        let u_frozen = <<T::BaseType as PyClass>::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;
372        if t_not_frozen && u_frozen {
373            // If `T` is mutable subclass of `U` differ, then it is possible that we need to
374            // release the borrow count now. (e.g. `U` may have a noop borrow checker so
375            // dropping the `PyRef<U>` later would noop and leak the borrow we currently hold.)
376            //
377            // However it's nontrivial, if `U` itself has a mutable base class `V`,
378            // then the borrow checker of both `T` and `U` is the shared borrow checker of `V`.
379            //
380            // But it's really hard to prove that in the type system, the soundest thing we
381            // can do is just add a borrow to `U` now and then release the borrow of `T`.
382
383            self.inner
384                .as_super()
385                .get_class_object()
386                .borrow_checker()
387                .try_borrow()
388                .expect("this object is already borrowed");
389
390            self.inner
391                .get_class_object()
392                .borrow_checker()
393                .release_borrow()
394        };
395        PyRef {
396            inner: unsafe {
397                ManuallyDrop::new(self)
398                    .as_ptr()
399                    .assume_owned_unchecked(py)
400                    .cast_into_unchecked()
401            },
402        }
403    }
404
405    /// Borrows a shared reference to `PyRef<T::BaseType>`.
406    ///
407    /// With the help of this method, you can access attributes and call methods
408    /// on the superclass without consuming the `PyRef<T>`. This method can also
409    /// be chained to access the super-superclass (and so on).
410    ///
411    /// # Examples
412    /// ```
413    /// # use pyo3::prelude::*;
414    /// #[pyclass(subclass)]
415    /// struct Base {
416    ///     base_name: &'static str,
417    /// }
418    /// #[pymethods]
419    /// impl Base {
420    ///     fn base_name_len(&self) -> usize {
421    ///         self.base_name.len()
422    ///     }
423    /// }
424    ///
425    /// #[pyclass(extends=Base)]
426    /// struct Sub {
427    ///     sub_name: &'static str,
428    /// }
429    ///
430    /// #[pymethods]
431    /// impl Sub {
432    ///     #[new]
433    ///     fn new() -> (Self, Base) {
434    ///         (Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
435    ///     }
436    ///     fn sub_name_len(&self) -> usize {
437    ///         self.sub_name.len()
438    ///     }
439    ///     fn format_name_lengths(slf: PyRef<'_, Self>) -> String {
440    ///         format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
441    ///     }
442    /// }
443    /// # Python::attach(|py| {
444    /// #     let sub = Py::new(py, Sub::new()).unwrap();
445    /// #     pyo3::py_run!(py, sub, "assert sub.format_name_lengths() == '9 8'")
446    /// # });
447    /// ```
448    pub fn as_super(&self) -> &PyRef<'p, T::BaseType> {
449        let ptr = NonNull::from(&self.inner)
450            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
451            .cast::<Bound<'p, T::BaseType>>()
452            // `Bound<T::BaseType>` has the same layout as `PyRef<T::BaseType>`
453            .cast::<PyRef<'p, T::BaseType>>();
454        // SAFETY: lifetimes are correctly transferred, and `PyRef<T>` and `PyRef<U>` have the same layout
455        unsafe { ptr.as_ref() }
456    }
457}
458
459impl<T: PyClass> Deref for PyRef<'_, T> {
460    type Target = T;
461
462    #[inline]
463    fn deref(&self) -> &T {
464        unsafe { &*self.inner.get_class_object().get_ptr() }
465    }
466}
467
468impl<T: PyClass> Drop for PyRef<'_, T> {
469    fn drop(&mut self) {
470        self.inner
471            .get_class_object()
472            .borrow_checker()
473            .release_borrow()
474    }
475}
476
477impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> {
478    type Target = T;
479    type Output = Bound<'py, T>;
480    type Error = Infallible;
481
482    #[cfg(feature = "experimental-inspect")]
483    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
484
485    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
486        Ok(self.inner.clone())
487    }
488}
489
490impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> {
491    type Target = T;
492    type Output = Borrowed<'a, 'py, T>;
493    type Error = Infallible;
494
495    #[cfg(feature = "experimental-inspect")]
496    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
497
498    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
499        Ok(self.inner.as_borrowed())
500    }
501}
502
503impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
504    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
505        fmt::Debug::fmt(&**self, f)
506    }
507}
508
509impl<'py, T: PyClass> TryFrom<&Bound<'py, T>> for PyRef<'py, T> {
510    type Error = PyBorrowError;
511    #[inline]
512    fn try_from(value: &Bound<'py, T>) -> Result<Self, Self::Error> {
513        PyRef::try_borrow(value)
514    }
515}
516
517/// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`].
518///
519/// See the [module-level documentation](self) for more information.
520#[repr(transparent)]
521pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
522    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
523    // store `Borrowed` here instead, avoiding reference counting overhead.
524    inner: Bound<'p, T>,
525}
526
527impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
528    /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
529    pub fn py(&self) -> Python<'p> {
530        self.inner.py()
531    }
532}
533
534impl<T> AsRef<T::BaseType> for PyRefMut<'_, T>
535where
536    T: PyClass<Frozen = False>,
537    T::BaseType: PyClass<Frozen = False>,
538{
539    fn as_ref(&self) -> &T::BaseType {
540        PyRefMut::downgrade(self).as_super()
541    }
542}
543
544impl<T> AsMut<T::BaseType> for PyRefMut<'_, T>
545where
546    T: PyClass<Frozen = False>,
547    T::BaseType: PyClass<Frozen = False>,
548{
549    fn as_mut(&mut self) -> &mut T::BaseType {
550        self.as_super()
551    }
552}
553
554impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> {
555    /// Returns the raw FFI pointer represented by self.
556    ///
557    /// # Safety
558    ///
559    /// Callers are responsible for ensuring that the pointer does not outlive self.
560    ///
561    /// The reference is borrowed; callers should not decrease the reference count
562    /// when they are finished with the pointer.
563    #[inline]
564    pub fn as_ptr(&self) -> *mut ffi::PyObject {
565        self.inner.as_ptr()
566    }
567
568    /// Returns an owned raw FFI pointer represented by self.
569    ///
570    /// # Safety
571    ///
572    /// The reference is owned; when finished the caller should either transfer ownership
573    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
574    #[inline]
575    pub fn into_ptr(self) -> *mut ffi::PyObject {
576        self.inner.clone().into_ptr()
577    }
578
579    #[inline]
580    #[track_caller]
581    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
582        Self::try_borrow(obj).expect("Already borrowed")
583    }
584
585    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
586        let cell = obj.get_class_object();
587        cell.ensure_threadsafe();
588        cell.borrow_checker()
589            .try_borrow_mut()
590            .map(|_| Self { inner: obj.clone() })
591    }
592
593    pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
594        let ptr = NonNull::from(slf).cast();
595        // SAFETY: `PyRefMut<T>` and `PyRef<T>` have the same layout
596        unsafe { ptr.as_ref() }
597    }
598}
599
600impl<'p, T> PyRefMut<'p, T>
601where
602    T: PyClass<Frozen = False>,
603    T::BaseType: PyClass<Frozen = False>,
604{
605    /// Gets a `PyRef<T::BaseType>`.
606    ///
607    /// See [`PyRef::into_super`] for more.
608    pub fn into_super(self) -> PyRefMut<'p, T::BaseType> {
609        let py = self.py();
610        PyRefMut {
611            inner: unsafe {
612                ManuallyDrop::new(self)
613                    .as_ptr()
614                    .assume_owned_unchecked(py)
615                    .cast_into_unchecked()
616            },
617        }
618    }
619
620    /// Borrows a mutable reference to `PyRefMut<T::BaseType>`.
621    ///
622    /// With the help of this method, you can mutate attributes and call mutating
623    /// methods on the superclass without consuming the `PyRefMut<T>`. This method
624    /// can also be chained to access the super-superclass (and so on).
625    ///
626    /// See [`PyRef::as_super`] for more.
627    pub fn as_super(&mut self) -> &mut PyRefMut<'p, T::BaseType> {
628        let mut ptr = NonNull::from(&mut self.inner)
629            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
630            .cast::<Bound<'p, T::BaseType>>()
631            // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`,
632            // and the mutable borrow on `self` prevents aliasing
633            .cast::<PyRefMut<'p, T::BaseType>>();
634        // SAFETY: lifetimes are correctly transferred, and `PyRefMut<T>` and `PyRefMut<U>` have the same layout
635        unsafe { ptr.as_mut() }
636    }
637}
638
639impl<T: PyClass<Frozen = False>> Deref for PyRefMut<'_, T> {
640    type Target = T;
641
642    #[inline]
643    fn deref(&self) -> &T {
644        unsafe { &*self.inner.get_class_object().get_ptr() }
645    }
646}
647
648impl<T: PyClass<Frozen = False>> DerefMut for PyRefMut<'_, T> {
649    #[inline]
650    fn deref_mut(&mut self) -> &mut T {
651        unsafe { &mut *self.inner.get_class_object().get_ptr() }
652    }
653}
654
655impl<T: PyClass<Frozen = False>> Drop for PyRefMut<'_, T> {
656    fn drop(&mut self) {
657        self.inner
658            .get_class_object()
659            .borrow_checker()
660            .release_borrow_mut()
661    }
662}
663
664impl<'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for PyRefMut<'py, T> {
665    type Target = T;
666    type Output = Bound<'py, T>;
667    type Error = Infallible;
668
669    #[cfg(feature = "experimental-inspect")]
670    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
671
672    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
673        Ok(self.inner.clone())
674    }
675}
676
677impl<'a, 'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for &'a PyRefMut<'py, T> {
678    type Target = T;
679    type Output = Borrowed<'a, 'py, T>;
680    type Error = Infallible;
681
682    #[cfg(feature = "experimental-inspect")]
683    const OUTPUT_TYPE: PyStaticExpr = T::TYPE_HINT;
684
685    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
686        Ok(self.inner.as_borrowed())
687    }
688}
689
690impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
691    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692        fmt::Debug::fmt(self.deref(), f)
693    }
694}
695
696impl<'py, T: PyClass<Frozen = False>> TryFrom<&Bound<'py, T>> for PyRefMut<'py, T> {
697    type Error = PyBorrowMutError;
698    #[inline]
699    fn try_from(value: &Bound<'py, T>) -> Result<Self, Self::Error> {
700        PyRefMut::try_borrow(value)
701    }
702}
703
704/// An error type returned by [`Bound::try_borrow`].
705///
706/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
707pub struct PyBorrowError {
708    _private: (),
709}
710
711impl PyBorrowError {
712    pub(crate) fn new() -> Self {
713        Self { _private: () }
714    }
715}
716
717impl fmt::Debug for PyBorrowError {
718    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
719        f.debug_struct("PyBorrowError").finish()
720    }
721}
722
723impl fmt::Display for PyBorrowError {
724    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
725        fmt::Display::fmt("Already mutably borrowed", f)
726    }
727}
728
729impl From<PyBorrowError> for PyErr {
730    fn from(other: PyBorrowError) -> Self {
731        PyRuntimeError::new_err(other.to_string())
732    }
733}
734
735/// An error type returned by [`Bound::try_borrow_mut`].
736///
737/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
738pub struct PyBorrowMutError {
739    _private: (),
740}
741
742impl PyBorrowMutError {
743    pub(crate) fn new() -> Self {
744        Self { _private: () }
745    }
746}
747
748impl fmt::Debug for PyBorrowMutError {
749    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
750        f.debug_struct("PyBorrowMutError").finish()
751    }
752}
753
754impl fmt::Display for PyBorrowMutError {
755    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
756        fmt::Display::fmt("Already borrowed", f)
757    }
758}
759
760impl From<PyBorrowMutError> for PyErr {
761    fn from(other: PyBorrowMutError) -> Self {
762        PyRuntimeError::new_err(other.to_string())
763    }
764}
765
766#[cfg(test)]
767#[cfg(feature = "macros")]
768mod tests {
769
770    use super::*;
771
772    #[crate::pyclass(skip_from_py_object)]
773    #[pyo3(crate = "crate")]
774    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
775    struct SomeClass(i32);
776
777    #[test]
778    fn test_as_ptr() {
779        Python::attach(|py| {
780            let cell = Bound::new(py, SomeClass(0)).unwrap();
781            let ptr = cell.as_ptr();
782
783            assert_eq!(cell.borrow().as_ptr(), ptr);
784            assert_eq!(cell.borrow_mut().as_ptr(), ptr);
785        })
786    }
787
788    #[test]
789    fn test_into_ptr() {
790        Python::attach(|py| {
791            let cell = Bound::new(py, SomeClass(0)).unwrap();
792            let ptr = cell.as_ptr();
793
794            assert_eq!(cell.borrow().into_ptr(), ptr);
795            unsafe { ffi::Py_DECREF(ptr) };
796
797            assert_eq!(cell.borrow_mut().into_ptr(), ptr);
798            unsafe { ffi::Py_DECREF(ptr) };
799        })
800    }
801
802    #[crate::pyclass]
803    #[pyo3(crate = "crate", subclass)]
804    struct BaseClass {
805        val1: usize,
806    }
807
808    #[crate::pyclass]
809    #[pyo3(crate = "crate", extends=BaseClass, subclass)]
810    struct SubClass {
811        val2: usize,
812    }
813
814    #[crate::pyclass]
815    #[pyo3(crate = "crate", extends=SubClass)]
816    struct SubSubClass {
817        val3: usize,
818    }
819
820    #[crate::pymethods]
821    #[pyo3(crate = "crate")]
822    impl SubSubClass {
823        #[new]
824        fn new(py: Python<'_>) -> crate::Py<SubSubClass> {
825            let init = crate::PyClassInitializer::from(BaseClass { val1: 10 })
826                .add_subclass(SubClass { val2: 15 })
827                .add_subclass(SubSubClass { val3: 20 });
828            crate::Py::new(py, init).expect("allocation error")
829        }
830
831        fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) {
832            let val1 = self_.as_super().as_super().val1;
833            let val2 = self_.as_super().val2;
834            (val1, val2, self_.val3)
835        }
836
837        fn double_values(mut self_: PyRefMut<'_, Self>) {
838            self_.as_super().as_super().val1 *= 2;
839            self_.as_super().val2 *= 2;
840            self_.val3 *= 2;
841        }
842    }
843
844    #[test]
845    fn test_pyref_as_super() {
846        Python::attach(|py| {
847            let obj = SubSubClass::new(py).into_bound(py);
848            let pyref = obj.borrow();
849            assert_eq!(pyref.as_super().as_super().val1, 10);
850            assert_eq!(pyref.as_super().val2, 15);
851            assert_eq!(pyref.as_ref().val2, 15); // `as_ref` also works
852            assert_eq!(pyref.val3, 20);
853            assert_eq!(SubSubClass::get_values(pyref), (10, 15, 20));
854        });
855    }
856
857    #[test]
858    fn test_pyrefmut_as_super() {
859        Python::attach(|py| {
860            let obj = SubSubClass::new(py).into_bound(py);
861            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 15, 20));
862            {
863                let mut pyrefmut = obj.borrow_mut();
864                assert_eq!(pyrefmut.as_super().as_ref().val1, 10);
865                pyrefmut.as_super().as_super().val1 -= 5;
866                pyrefmut.as_super().val2 -= 3;
867                pyrefmut.as_mut().val2 -= 2; // `as_mut` also works
868                pyrefmut.val3 -= 5;
869            }
870            assert_eq!(SubSubClass::get_values(obj.borrow()), (5, 10, 15));
871            SubSubClass::double_values(obj.borrow_mut());
872            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 20, 30));
873        });
874    }
875
876    #[test]
877    fn test_pyrefs_in_python() {
878        Python::attach(|py| {
879            let obj = SubSubClass::new(py);
880            crate::py_run!(py, obj, "assert obj.get_values() == (10, 15, 20)");
881            crate::py_run!(py, obj, "assert obj.double_values() is None");
882            crate::py_run!(py, obj, "assert obj.get_values() == (20, 30, 40)");
883        });
884    }
885
886    #[test]
887    fn test_into_frozen_super_released_borrow() {
888        #[crate::pyclass]
889        #[pyo3(crate = "crate", subclass, frozen)]
890        struct BaseClass {}
891
892        #[crate::pyclass]
893        #[pyo3(crate = "crate", extends=BaseClass, subclass)]
894        struct SubClass {}
895
896        #[crate::pymethods]
897        #[pyo3(crate = "crate")]
898        impl SubClass {
899            #[new]
900            fn new(py: Python<'_>) -> Bound<'_, SubClass> {
901                let init = crate::PyClassInitializer::from(BaseClass {}).add_subclass(SubClass {});
902                Bound::new(py, init).expect("allocation error")
903            }
904        }
905
906        Python::attach(|py| {
907            let obj = SubClass::new(py);
908            drop(obj.borrow().into_super());
909            assert!(obj.try_borrow_mut().is_ok());
910        })
911    }
912
913    #[test]
914    fn test_into_frozen_super_mutable_base_holds_borrow() {
915        #[crate::pyclass]
916        #[pyo3(crate = "crate", subclass)]
917        struct BaseClass {}
918
919        #[crate::pyclass]
920        #[pyo3(crate = "crate", extends=BaseClass, subclass, frozen)]
921        struct SubClass {}
922
923        #[crate::pyclass]
924        #[pyo3(crate = "crate", extends=SubClass, subclass)]
925        struct SubSubClass {}
926
927        #[crate::pymethods]
928        #[pyo3(crate = "crate")]
929        impl SubSubClass {
930            #[new]
931            fn new(py: Python<'_>) -> Bound<'_, SubSubClass> {
932                let init = crate::PyClassInitializer::from(BaseClass {})
933                    .add_subclass(SubClass {})
934                    .add_subclass(SubSubClass {});
935                Bound::new(py, init).expect("allocation error")
936            }
937        }
938
939        Python::attach(|py| {
940            let obj = SubSubClass::new(py);
941            let _super_borrow = obj.borrow().into_super();
942            // the whole object still has an immutable borrow, so we cannot
943            // borrow any part mutably (the borrowflag is shared)
944            assert!(obj.try_borrow_mut().is_err());
945        })
946    }
947}