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
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//!             .downcast::<_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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::{AsPyPointer, IntoPyObject};
197use crate::exceptions::PyRuntimeError;
198use crate::ffi_ptr_ext::FfiPtrExt;
199use crate::internal_tricks::{ptr_from_mut, ptr_from_ref};
200use crate::pyclass::{boolean_struct::False, PyClass};
201use crate::types::any::PyAnyMethods;
202#[allow(deprecated)]
203use crate::IntoPy;
204use crate::{ffi, Borrowed, Bound, PyErr, PyObject, Python};
205use std::convert::Infallible;
206use std::fmt;
207use std::mem::ManuallyDrop;
208use std::ops::{Deref, DerefMut};
209
210pub(crate) mod impl_;
211use impl_::{PyClassBorrowChecker, PyClassObjectLayout};
212
213/// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`].
214///
215/// See the [`Bound`] documentation for more information.
216///
217/// # Examples
218///
219/// You can use [`PyRef`] as an alternative to a `&self` receiver when
220/// - you need to access the pointer of the [`Bound`], or
221/// - you want to get a super class.
222/// ```
223/// # use pyo3::prelude::*;
224/// #[pyclass(subclass)]
225/// struct Parent {
226///     basename: &'static str,
227/// }
228///
229/// #[pyclass(extends=Parent)]
230/// struct Child {
231///     name: &'static str,
232///  }
233///
234/// #[pymethods]
235/// impl Child {
236///     #[new]
237///     fn new() -> (Self, Parent) {
238///         (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
239///     }
240///
241///     fn format(slf: PyRef<'_, Self>) -> String {
242///         // We can get *mut ffi::PyObject from PyRef
243///         let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
244///         // We can get &Self::BaseType by as_ref
245///         let basename = slf.as_ref().basename;
246///         format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
247///     }
248/// }
249/// # Python::with_gil(|py| {
250/// #     let sub = Py::new(py, Child::new()).unwrap();
251/// #     pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()");
252/// # });
253/// ```
254///
255/// See the [module-level documentation](self) for more information.
256#[repr(transparent)]
257pub struct PyRef<'p, T: PyClass> {
258    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
259    // store `Borrowed` here instead, avoiding reference counting overhead.
260    inner: Bound<'p, T>,
261}
262
263impl<'p, T: PyClass> PyRef<'p, T> {
264    /// Returns a `Python` token that is bound to the lifetime of the `PyRef`.
265    pub fn py(&self) -> Python<'p> {
266        self.inner.py()
267    }
268}
269
270impl<T, U> AsRef<U> for PyRef<'_, T>
271where
272    T: PyClass<BaseType = U>,
273    U: PyClass,
274{
275    fn as_ref(&self) -> &T::BaseType {
276        self.as_super()
277    }
278}
279
280impl<'py, T: PyClass> PyRef<'py, T> {
281    /// Returns the raw FFI pointer represented by self.
282    ///
283    /// # Safety
284    ///
285    /// Callers are responsible for ensuring that the pointer does not outlive self.
286    ///
287    /// The reference is borrowed; callers should not decrease the reference count
288    /// when they are finished with the pointer.
289    #[inline]
290    pub fn as_ptr(&self) -> *mut ffi::PyObject {
291        self.inner.as_ptr()
292    }
293
294    /// Returns an owned raw FFI pointer represented by self.
295    ///
296    /// # Safety
297    ///
298    /// The reference is owned; when finished the caller should either transfer ownership
299    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
300    #[inline]
301    pub fn into_ptr(self) -> *mut ffi::PyObject {
302        self.inner.clone().into_ptr()
303    }
304
305    #[track_caller]
306    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
307        Self::try_borrow(obj).expect("Already mutably borrowed")
308    }
309
310    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowError> {
311        let cell = obj.get_class_object();
312        cell.ensure_threadsafe();
313        cell.borrow_checker()
314            .try_borrow()
315            .map(|_| Self { inner: obj.clone() })
316    }
317}
318
319impl<'p, T, U> PyRef<'p, T>
320where
321    T: PyClass<BaseType = U>,
322    U: PyClass,
323{
324    /// Gets a `PyRef<T::BaseType>`.
325    ///
326    /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be
327    /// used to get the base of `T::BaseType`.
328    ///
329    /// But with the help of this method, you can get hold of instances of the
330    /// super-superclass when needed.
331    ///
332    /// # Examples
333    /// ```
334    /// # use pyo3::prelude::*;
335    /// #[pyclass(subclass)]
336    /// struct Base1 {
337    ///     name1: &'static str,
338    /// }
339    ///
340    /// #[pyclass(extends=Base1, subclass)]
341    /// struct Base2 {
342    ///     name2: &'static str,
343    /// }
344    ///
345    /// #[pyclass(extends=Base2)]
346    /// struct Sub {
347    ///     name3: &'static str,
348    /// }
349    ///
350    /// #[pymethods]
351    /// impl Sub {
352    ///     #[new]
353    ///     fn new() -> PyClassInitializer<Self> {
354    ///         PyClassInitializer::from(Base1 { name1: "base1" })
355    ///             .add_subclass(Base2 { name2: "base2" })
356    ///             .add_subclass(Self { name3: "sub" })
357    ///     }
358    ///     fn name(slf: PyRef<'_, Self>) -> String {
359    ///         let subname = slf.name3;
360    ///         let super_ = slf.into_super();
361    ///         format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
362    ///     }
363    /// }
364    /// # Python::with_gil(|py| {
365    /// #     let sub = Py::new(py, Sub::new()).unwrap();
366    /// #     pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
367    /// # });
368    /// ```
369    pub fn into_super(self) -> PyRef<'p, U> {
370        let py = self.py();
371        PyRef {
372            inner: unsafe {
373                ManuallyDrop::new(self)
374                    .as_ptr()
375                    .assume_owned_unchecked(py)
376                    .downcast_into_unchecked()
377            },
378        }
379    }
380
381    /// Borrows a shared reference to `PyRef<T::BaseType>`.
382    ///
383    /// With the help of this method, you can access attributes and call methods
384    /// on the superclass without consuming the `PyRef<T>`. This method can also
385    /// be chained to access the super-superclass (and so on).
386    ///
387    /// # Examples
388    /// ```
389    /// # use pyo3::prelude::*;
390    /// #[pyclass(subclass)]
391    /// struct Base {
392    ///     base_name: &'static str,
393    /// }
394    /// #[pymethods]
395    /// impl Base {
396    ///     fn base_name_len(&self) -> usize {
397    ///         self.base_name.len()
398    ///     }
399    /// }
400    ///
401    /// #[pyclass(extends=Base)]
402    /// struct Sub {
403    ///     sub_name: &'static str,
404    /// }
405    ///
406    /// #[pymethods]
407    /// impl Sub {
408    ///     #[new]
409    ///     fn new() -> (Self, Base) {
410    ///         (Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
411    ///     }
412    ///     fn sub_name_len(&self) -> usize {
413    ///         self.sub_name.len()
414    ///     }
415    ///     fn format_name_lengths(slf: PyRef<'_, Self>) -> String {
416    ///         format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
417    ///     }
418    /// }
419    /// # Python::with_gil(|py| {
420    /// #     let sub = Py::new(py, Sub::new()).unwrap();
421    /// #     pyo3::py_run!(py, sub, "assert sub.format_name_lengths() == '9 8'")
422    /// # });
423    /// ```
424    pub fn as_super(&self) -> &PyRef<'p, U> {
425        let ptr = ptr_from_ref::<Bound<'p, T>>(&self.inner)
426            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
427            .cast::<Bound<'p, T::BaseType>>()
428            // `Bound<T::BaseType>` has the same layout as `PyRef<T::BaseType>`
429            .cast::<PyRef<'p, T::BaseType>>();
430        unsafe { &*ptr }
431    }
432}
433
434impl<T: PyClass> Deref for PyRef<'_, T> {
435    type Target = T;
436
437    #[inline]
438    fn deref(&self) -> &T {
439        unsafe { &*self.inner.get_class_object().get_ptr() }
440    }
441}
442
443impl<T: PyClass> Drop for PyRef<'_, T> {
444    fn drop(&mut self) {
445        self.inner
446            .get_class_object()
447            .borrow_checker()
448            .release_borrow()
449    }
450}
451
452#[allow(deprecated)]
453impl<T: PyClass> IntoPy<PyObject> for PyRef<'_, T> {
454    fn into_py(self, py: Python<'_>) -> PyObject {
455        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
456    }
457}
458
459#[allow(deprecated)]
460impl<T: PyClass> IntoPy<PyObject> for &'_ PyRef<'_, T> {
461    fn into_py(self, py: Python<'_>) -> PyObject {
462        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
463    }
464}
465
466impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> {
467    type Target = T;
468    type Output = Bound<'py, T>;
469    type Error = Infallible;
470
471    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
472        Ok(self.inner.clone())
473    }
474}
475
476impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> {
477    type Target = T;
478    type Output = Borrowed<'a, 'py, T>;
479    type Error = Infallible;
480
481    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
482        Ok(self.inner.as_borrowed())
483    }
484}
485
486unsafe impl<T: PyClass> AsPyPointer for PyRef<'_, T> {
487    fn as_ptr(&self) -> *mut ffi::PyObject {
488        self.inner.as_ptr()
489    }
490}
491
492impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
493    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
494        fmt::Debug::fmt(&**self, f)
495    }
496}
497
498/// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`].
499///
500/// See the [module-level documentation](self) for more information.
501#[repr(transparent)]
502pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
503    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
504    // store `Borrowed` here instead, avoiding reference counting overhead.
505    inner: Bound<'p, T>,
506}
507
508impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
509    /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
510    pub fn py(&self) -> Python<'p> {
511        self.inner.py()
512    }
513}
514
515impl<T, U> AsRef<U> for PyRefMut<'_, T>
516where
517    T: PyClass<BaseType = U, Frozen = False>,
518    U: PyClass<Frozen = False>,
519{
520    fn as_ref(&self) -> &T::BaseType {
521        PyRefMut::downgrade(self).as_super()
522    }
523}
524
525impl<T, U> AsMut<U> for PyRefMut<'_, T>
526where
527    T: PyClass<BaseType = U, Frozen = False>,
528    U: PyClass<Frozen = False>,
529{
530    fn as_mut(&mut self) -> &mut T::BaseType {
531        self.as_super()
532    }
533}
534
535impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> {
536    /// Returns the raw FFI pointer represented by self.
537    ///
538    /// # Safety
539    ///
540    /// Callers are responsible for ensuring that the pointer does not outlive self.
541    ///
542    /// The reference is borrowed; callers should not decrease the reference count
543    /// when they are finished with the pointer.
544    #[inline]
545    pub fn as_ptr(&self) -> *mut ffi::PyObject {
546        self.inner.as_ptr()
547    }
548
549    /// Returns an owned raw FFI pointer represented by self.
550    ///
551    /// # Safety
552    ///
553    /// The reference is owned; when finished the caller should either transfer ownership
554    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
555    #[inline]
556    pub fn into_ptr(self) -> *mut ffi::PyObject {
557        self.inner.clone().into_ptr()
558    }
559
560    #[inline]
561    #[track_caller]
562    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
563        Self::try_borrow(obj).expect("Already borrowed")
564    }
565
566    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
567        let cell = obj.get_class_object();
568        cell.ensure_threadsafe();
569        cell.borrow_checker()
570            .try_borrow_mut()
571            .map(|_| Self { inner: obj.clone() })
572    }
573
574    pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
575        // `PyRefMut<T>` and `PyRef<T>` have the same layout
576        unsafe { &*ptr_from_ref(slf).cast() }
577    }
578}
579
580impl<'p, T, U> PyRefMut<'p, T>
581where
582    T: PyClass<BaseType = U, Frozen = False>,
583    U: PyClass<Frozen = False>,
584{
585    /// Gets a `PyRef<T::BaseType>`.
586    ///
587    /// See [`PyRef::into_super`] for more.
588    pub fn into_super(self) -> PyRefMut<'p, U> {
589        let py = self.py();
590        PyRefMut {
591            inner: unsafe {
592                ManuallyDrop::new(self)
593                    .as_ptr()
594                    .assume_owned_unchecked(py)
595                    .downcast_into_unchecked()
596            },
597        }
598    }
599
600    /// Borrows a mutable reference to `PyRefMut<T::BaseType>`.
601    ///
602    /// With the help of this method, you can mutate attributes and call mutating
603    /// methods on the superclass without consuming the `PyRefMut<T>`. This method
604    /// can also be chained to access the super-superclass (and so on).
605    ///
606    /// See [`PyRef::as_super`] for more.
607    pub fn as_super(&mut self) -> &mut PyRefMut<'p, U> {
608        let ptr = ptr_from_mut::<Bound<'p, T>>(&mut self.inner)
609            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
610            .cast::<Bound<'p, T::BaseType>>()
611            // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`,
612            // and the mutable borrow on `self` prevents aliasing
613            .cast::<PyRefMut<'p, T::BaseType>>();
614        unsafe { &mut *ptr }
615    }
616}
617
618impl<T: PyClass<Frozen = False>> Deref for PyRefMut<'_, T> {
619    type Target = T;
620
621    #[inline]
622    fn deref(&self) -> &T {
623        unsafe { &*self.inner.get_class_object().get_ptr() }
624    }
625}
626
627impl<T: PyClass<Frozen = False>> DerefMut for PyRefMut<'_, T> {
628    #[inline]
629    fn deref_mut(&mut self) -> &mut T {
630        unsafe { &mut *self.inner.get_class_object().get_ptr() }
631    }
632}
633
634impl<T: PyClass<Frozen = False>> Drop for PyRefMut<'_, T> {
635    fn drop(&mut self) {
636        self.inner
637            .get_class_object()
638            .borrow_checker()
639            .release_borrow_mut()
640    }
641}
642
643#[allow(deprecated)]
644impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for PyRefMut<'_, T> {
645    fn into_py(self, py: Python<'_>) -> PyObject {
646        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
647    }
648}
649
650#[allow(deprecated)]
651impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for &'_ PyRefMut<'_, T> {
652    fn into_py(self, py: Python<'_>) -> PyObject {
653        self.inner.clone().into_py(py)
654    }
655}
656
657impl<'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for PyRefMut<'py, T> {
658    type Target = T;
659    type Output = Bound<'py, T>;
660    type Error = Infallible;
661
662    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
663        Ok(self.inner.clone())
664    }
665}
666
667impl<'a, 'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for &'a PyRefMut<'py, T> {
668    type Target = T;
669    type Output = Borrowed<'a, 'py, T>;
670    type Error = Infallible;
671
672    fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
673        Ok(self.inner.as_borrowed())
674    }
675}
676
677impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
678    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
679        fmt::Debug::fmt(self.deref(), f)
680    }
681}
682
683/// An error type returned by [`Bound::try_borrow`].
684///
685/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
686pub struct PyBorrowError {
687    _private: (),
688}
689
690impl fmt::Debug for PyBorrowError {
691    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
692        f.debug_struct("PyBorrowError").finish()
693    }
694}
695
696impl fmt::Display for PyBorrowError {
697    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
698        fmt::Display::fmt("Already mutably borrowed", f)
699    }
700}
701
702impl From<PyBorrowError> for PyErr {
703    fn from(other: PyBorrowError) -> Self {
704        PyRuntimeError::new_err(other.to_string())
705    }
706}
707
708/// An error type returned by [`Bound::try_borrow_mut`].
709///
710/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
711pub struct PyBorrowMutError {
712    _private: (),
713}
714
715impl fmt::Debug for PyBorrowMutError {
716    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
717        f.debug_struct("PyBorrowMutError").finish()
718    }
719}
720
721impl fmt::Display for PyBorrowMutError {
722    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
723        fmt::Display::fmt("Already borrowed", f)
724    }
725}
726
727impl From<PyBorrowMutError> for PyErr {
728    fn from(other: PyBorrowMutError) -> Self {
729        PyRuntimeError::new_err(other.to_string())
730    }
731}
732
733#[cfg(test)]
734#[cfg(feature = "macros")]
735mod tests {
736
737    use super::*;
738
739    #[crate::pyclass]
740    #[pyo3(crate = "crate")]
741    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
742    struct SomeClass(i32);
743
744    #[test]
745    fn test_as_ptr() {
746        Python::with_gil(|py| {
747            let cell = Bound::new(py, SomeClass(0)).unwrap();
748            let ptr = cell.as_ptr();
749
750            assert_eq!(cell.borrow().as_ptr(), ptr);
751            assert_eq!(cell.borrow_mut().as_ptr(), ptr);
752        })
753    }
754
755    #[test]
756    fn test_into_ptr() {
757        Python::with_gil(|py| {
758            let cell = Bound::new(py, SomeClass(0)).unwrap();
759            let ptr = cell.as_ptr();
760
761            assert_eq!(cell.borrow().into_ptr(), ptr);
762            unsafe { ffi::Py_DECREF(ptr) };
763
764            assert_eq!(cell.borrow_mut().into_ptr(), ptr);
765            unsafe { ffi::Py_DECREF(ptr) };
766        })
767    }
768
769    #[crate::pyclass]
770    #[pyo3(crate = "crate", subclass)]
771    struct BaseClass {
772        val1: usize,
773    }
774
775    #[crate::pyclass]
776    #[pyo3(crate = "crate", extends=BaseClass, subclass)]
777    struct SubClass {
778        val2: usize,
779    }
780
781    #[crate::pyclass]
782    #[pyo3(crate = "crate", extends=SubClass)]
783    struct SubSubClass {
784        val3: usize,
785    }
786
787    #[crate::pymethods]
788    #[pyo3(crate = "crate")]
789    impl SubSubClass {
790        #[new]
791        fn new(py: Python<'_>) -> crate::Py<SubSubClass> {
792            let init = crate::PyClassInitializer::from(BaseClass { val1: 10 })
793                .add_subclass(SubClass { val2: 15 })
794                .add_subclass(SubSubClass { val3: 20 });
795            crate::Py::new(py, init).expect("allocation error")
796        }
797
798        fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) {
799            let val1 = self_.as_super().as_super().val1;
800            let val2 = self_.as_super().val2;
801            (val1, val2, self_.val3)
802        }
803
804        fn double_values(mut self_: PyRefMut<'_, Self>) {
805            self_.as_super().as_super().val1 *= 2;
806            self_.as_super().val2 *= 2;
807            self_.val3 *= 2;
808        }
809    }
810
811    #[test]
812    fn test_pyref_as_super() {
813        Python::with_gil(|py| {
814            let obj = SubSubClass::new(py).into_bound(py);
815            let pyref = obj.borrow();
816            assert_eq!(pyref.as_super().as_super().val1, 10);
817            assert_eq!(pyref.as_super().val2, 15);
818            assert_eq!(pyref.as_ref().val2, 15); // `as_ref` also works
819            assert_eq!(pyref.val3, 20);
820            assert_eq!(SubSubClass::get_values(pyref), (10, 15, 20));
821        });
822    }
823
824    #[test]
825    fn test_pyrefmut_as_super() {
826        Python::with_gil(|py| {
827            let obj = SubSubClass::new(py).into_bound(py);
828            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 15, 20));
829            {
830                let mut pyrefmut = obj.borrow_mut();
831                assert_eq!(pyrefmut.as_super().as_ref().val1, 10);
832                pyrefmut.as_super().as_super().val1 -= 5;
833                pyrefmut.as_super().val2 -= 3;
834                pyrefmut.as_mut().val2 -= 2; // `as_mut` also works
835                pyrefmut.val3 -= 5;
836            }
837            assert_eq!(SubSubClass::get_values(obj.borrow()), (5, 10, 15));
838            SubSubClass::double_values(obj.borrow_mut());
839            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 20, 30));
840        });
841    }
842
843    #[test]
844    fn test_pyrefs_in_python() {
845        Python::with_gil(|py| {
846            let obj = SubSubClass::new(py);
847            crate::py_run!(py, obj, "assert obj.get_values() == (10, 15, 20)");
848            crate::py_run!(py, obj, "assert obj.double_values() is None");
849            crate::py_run!(py, obj, "assert obj.get_values() == (20, 30, 40)");
850        });
851    }
852}
⚠️ Internal Docs ⚠️ Not Public API 👉 Official Docs Here