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 threadsafe 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::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_bound!(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_bound!(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_bound!(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;
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#[cfg(feature = "gil-refs")]
203use crate::{
204    conversion::ToPyObject,
205    impl_::pyclass::PyClassImpl,
206    pyclass::boolean_struct::True,
207    pyclass_init::PyClassInitializer,
208    type_object::{PyLayout, PySizedLayout},
209    types::PyAny,
210    PyNativeType, PyResult, PyTypeCheck,
211};
212use crate::{ffi, Bound, IntoPy, PyErr, PyObject, Python};
213use std::fmt;
214use std::mem::ManuallyDrop;
215use std::ops::{Deref, DerefMut};
216
217pub(crate) mod impl_;
218#[cfg(feature = "gil-refs")]
219use self::impl_::PyClassObject;
220use impl_::{PyClassBorrowChecker, PyClassObjectLayout};
221
222/// A container type for (mutably) accessing [`PyClass`] values
223///
224/// `PyCell` autodereferences to [`PyAny`], so you can call `PyAny`'s methods on a `PyCell<T>`.
225///
226/// # Examples
227///
228/// This example demonstrates getting a mutable reference of the contained `PyClass`.
229/// ```rust
230/// use pyo3::prelude::*;
231///
232/// #[pyclass]
233/// struct Number {
234///     inner: u32,
235/// }
236///
237/// #[pymethods]
238/// impl Number {
239///     fn increment(&mut self) {
240///         self.inner += 1;
241///     }
242/// }
243///
244/// # fn main() -> PyResult<()> {
245/// Python::with_gil(|py| {
246/// #   #[allow(deprecated)]
247///     let n = PyCell::new(py, Number { inner: 0 })?;
248///
249///     let n_mutable: &mut Number = &mut n.borrow_mut();
250///     n_mutable.increment();
251///
252///     Ok(())
253/// })
254/// # }
255/// ```
256/// For more information on how, when and why (not) to use `PyCell` please see the
257/// [module-level documentation](self).
258#[cfg(feature = "gil-refs")]
259#[deprecated(
260    since = "0.21.0",
261    note = "`PyCell` was merged into `Bound`, use that instead; see the migration guide for more info"
262)]
263#[repr(transparent)]
264pub struct PyCell<T: PyClassImpl>(PyClassObject<T>);
265
266#[cfg(feature = "gil-refs")]
267#[allow(deprecated)]
268unsafe impl<T: PyClass> PyNativeType for PyCell<T> {
269    type AsRefSource = T;
270}
271
272#[cfg(feature = "gil-refs")]
273#[allow(deprecated)]
274impl<T: PyClass> PyCell<T> {
275    /// Makes a new `PyCell` on the Python heap and return the reference to it.
276    ///
277    /// In cases where the value in the cell does not need to be accessed immediately after
278    /// creation, consider [`Py::new`](crate::Py::new) as a more efficient alternative.
279    #[deprecated(
280        since = "0.21.0",
281        note = "use `Bound::new(py, value)` or `Py::new(py, value)` instead of `PyCell::new(py, value)`"
282    )]
283    pub fn new(py: Python<'_>, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self> {
284        Bound::new(py, value).map(Bound::into_gil_ref)
285    }
286
287    /// Immutably borrows the value `T`. This borrow lasts as long as the returned `PyRef` exists.
288    ///
289    /// For frozen classes, the simpler [`get`][Self::get] is available.
290    ///
291    /// # Panics
292    ///
293    /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
294    /// [`try_borrow`](#method.try_borrow).
295    pub fn borrow(&self) -> PyRef<'_, T> {
296        PyRef::borrow(&self.as_borrowed())
297    }
298
299    /// Mutably borrows the value `T`. This borrow lasts as long as the returned `PyRefMut` exists.
300    ///
301    /// # Panics
302    ///
303    /// Panics if the value is currently borrowed. For a non-panicking variant, use
304    /// [`try_borrow_mut`](#method.try_borrow_mut).
305    pub fn borrow_mut(&self) -> PyRefMut<'_, T>
306    where
307        T: PyClass<Frozen = False>,
308    {
309        PyRefMut::borrow(&self.as_borrowed())
310    }
311
312    /// Immutably borrows the value `T`, returning an error if the value is currently
313    /// mutably borrowed. This borrow lasts as long as the returned `PyRef` exists.
314    ///
315    /// This is the non-panicking variant of [`borrow`](#method.borrow).
316    ///
317    /// For frozen classes, the simpler [`get`][Self::get] is available.
318    ///
319    /// # Examples
320    ///
321    /// ```
322    /// # use pyo3::prelude::*;
323    /// #[pyclass]
324    /// struct Class {}
325    ///
326    /// Python::with_gil(|py| {
327    /// #   #[allow(deprecated)]
328    ///     let c = PyCell::new(py, Class {}).unwrap();
329    ///     {
330    ///         let m = c.borrow_mut();
331    ///         assert!(c.try_borrow().is_err());
332    ///     }
333    ///
334    ///     {
335    ///         let m = c.borrow();
336    ///         assert!(c.try_borrow().is_ok());
337    ///     }
338    /// });
339    /// ```
340    pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
341        PyRef::try_borrow(&self.as_borrowed())
342    }
343
344    /// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
345    /// This borrow lasts as long as the returned `PyRefMut` exists.
346    ///
347    /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
348    ///
349    /// # Examples
350    ///
351    /// ```
352    /// # use pyo3::prelude::*;
353    /// #[pyclass]
354    /// struct Class {}
355    /// Python::with_gil(|py| {
356    /// #   #[allow(deprecated)]
357    ///     let c = PyCell::new(py, Class {}).unwrap();
358    ///     {
359    ///         let m = c.borrow();
360    ///         assert!(c.try_borrow_mut().is_err());
361    ///     }
362    ///
363    ///     assert!(c.try_borrow_mut().is_ok());
364    /// });
365    /// ```
366    pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError>
367    where
368        T: PyClass<Frozen = False>,
369    {
370        PyRefMut::try_borrow(&self.as_borrowed())
371    }
372
373    /// Immutably borrows the value `T`, returning an error if the value is
374    /// currently mutably borrowed.
375    ///
376    /// # Safety
377    ///
378    /// This method is unsafe because it does not return a `PyRef`,
379    /// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
380    /// while the reference returned by this method is alive is undefined behaviour.
381    ///
382    /// # Examples
383    ///
384    /// ```
385    /// # use pyo3::prelude::*;
386    /// #[pyclass]
387    /// struct Class {}
388    /// Python::with_gil(|py| {
389    /// #   #[allow(deprecated)]
390    ///     let c = PyCell::new(py, Class {}).unwrap();
391    ///
392    ///     {
393    ///         let m = c.borrow_mut();
394    ///         assert!(unsafe { c.try_borrow_unguarded() }.is_err());
395    ///     }
396    ///
397    ///     {
398    ///         let m = c.borrow();
399    ///         assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
400    ///     }
401    /// });
402    /// ```
403    pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
404        self.0.ensure_threadsafe();
405        self.0
406            .borrow_checker()
407            .try_borrow_unguarded()
408            .map(|_: ()| &*self.0.get_ptr())
409    }
410
411    /// Provide an immutable borrow of the value `T` without acquiring the GIL.
412    ///
413    /// This is available if the class is [`frozen`][macro@crate::pyclass] and [`Sync`].
414    ///
415    /// While the GIL is usually required to get access to `&PyCell<T>`,
416    /// compared to [`borrow`][Self::borrow] or [`try_borrow`][Self::try_borrow]
417    /// this avoids any thread or borrow checking overhead at runtime.
418    ///
419    /// # Examples
420    ///
421    /// ```
422    /// use std::sync::atomic::{AtomicUsize, Ordering};
423    /// # use pyo3::prelude::*;
424    ///
425    /// #[pyclass(frozen)]
426    /// struct FrozenCounter {
427    ///     value: AtomicUsize,
428    /// }
429    ///
430    /// Python::with_gil(|py| {
431    ///     let counter = FrozenCounter { value: AtomicUsize::new(0) };
432    ///
433    /// #   #[allow(deprecated)]
434    ///     let cell = PyCell::new(py, counter).unwrap();
435    ///
436    ///     cell.get().value.fetch_add(1, Ordering::Relaxed);
437    /// });
438    /// ```
439    pub fn get(&self) -> &T
440    where
441        T: PyClass<Frozen = True> + Sync,
442    {
443        // SAFETY: The class itself is frozen and `Sync` and we do not access anything but `self.contents.value`.
444        unsafe { &*self.get_ptr() }
445    }
446
447    /// Replaces the wrapped value with a new one, returning the old value.
448    ///
449    /// # Panics
450    ///
451    /// Panics if the value is currently borrowed.
452    #[inline]
453    pub fn replace(&self, t: T) -> T
454    where
455        T: PyClass<Frozen = False>,
456    {
457        std::mem::replace(&mut *self.borrow_mut(), t)
458    }
459
460    /// Replaces the wrapped value with a new one computed from `f`, returning the old value.
461    ///
462    /// # Panics
463    ///
464    /// Panics if the value is currently borrowed.
465    pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T
466    where
467        T: PyClass<Frozen = False>,
468    {
469        let mut_borrow = &mut *self.borrow_mut();
470        let replacement = f(mut_borrow);
471        std::mem::replace(mut_borrow, replacement)
472    }
473
474    /// Swaps the wrapped value of `self` with the wrapped value of `other`.
475    ///
476    /// # Panics
477    ///
478    /// Panics if the value in either `PyCell` is currently borrowed.
479    #[inline]
480    pub fn swap(&self, other: &Self)
481    where
482        T: PyClass<Frozen = False>,
483    {
484        std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
485    }
486
487    pub(crate) fn get_ptr(&self) -> *mut T {
488        self.0.get_ptr()
489    }
490}
491
492#[cfg(feature = "gil-refs")]
493#[allow(deprecated)]
494unsafe impl<T: PyClassImpl> PyLayout<T> for PyCell<T> {}
495#[cfg(feature = "gil-refs")]
496#[allow(deprecated)]
497impl<T: PyClass> PySizedLayout<T> for PyCell<T> {}
498
499#[cfg(feature = "gil-refs")]
500#[allow(deprecated)]
501impl<T> PyTypeCheck for PyCell<T>
502where
503    T: PyClass,
504{
505    const NAME: &'static str = <T as PyTypeCheck>::NAME;
506
507    fn type_check(object: &Bound<'_, PyAny>) -> bool {
508        <T as PyTypeCheck>::type_check(object)
509    }
510}
511#[cfg(feature = "gil-refs")]
512#[allow(deprecated)]
513unsafe impl<T: PyClass> AsPyPointer for PyCell<T> {
514    fn as_ptr(&self) -> *mut ffi::PyObject {
515        ptr_from_ref(self) as *mut _
516    }
517}
518
519#[cfg(feature = "gil-refs")]
520#[allow(deprecated)]
521impl<T: PyClass> ToPyObject for &PyCell<T> {
522    fn to_object(&self, py: Python<'_>) -> PyObject {
523        unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
524    }
525}
526
527#[cfg(feature = "gil-refs")]
528#[allow(deprecated)]
529impl<T: PyClass> AsRef<PyAny> for PyCell<T> {
530    fn as_ref(&self) -> &PyAny {
531        #[allow(deprecated)]
532        unsafe {
533            self.py().from_borrowed_ptr(self.as_ptr())
534        }
535    }
536}
537
538#[cfg(feature = "gil-refs")]
539#[allow(deprecated)]
540impl<T: PyClass> Deref for PyCell<T> {
541    type Target = PyAny;
542
543    fn deref(&self) -> &PyAny {
544        #[allow(deprecated)]
545        unsafe {
546            self.py().from_borrowed_ptr(self.as_ptr())
547        }
548    }
549}
550
551#[cfg(feature = "gil-refs")]
552#[allow(deprecated)]
553impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
554    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
555        match self.try_borrow() {
556            Ok(borrow) => f.debug_struct("RefCell").field("value", &borrow).finish(),
557            Err(_) => {
558                struct BorrowedPlaceholder;
559                impl fmt::Debug for BorrowedPlaceholder {
560                    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
561                        f.write_str("<borrowed>")
562                    }
563                }
564                f.debug_struct("RefCell")
565                    .field("value", &BorrowedPlaceholder)
566                    .finish()
567            }
568        }
569    }
570}
571
572/// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`].
573///
574/// See the [`Bound`] documentation for more information.
575///
576/// # Examples
577///
578/// You can use [`PyRef`] as an alternative to a `&self` receiver when
579/// - you need to access the pointer of the [`Bound`], or
580/// - you want to get a super class.
581/// ```
582/// # use pyo3::prelude::*;
583/// #[pyclass(subclass)]
584/// struct Parent {
585///     basename: &'static str,
586/// }
587///
588/// #[pyclass(extends=Parent)]
589/// struct Child {
590///     name: &'static str,
591///  }
592///
593/// #[pymethods]
594/// impl Child {
595///     #[new]
596///     fn new() -> (Self, Parent) {
597///         (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
598///     }
599///
600///     fn format(slf: PyRef<'_, Self>) -> String {
601///         // We can get *mut ffi::PyObject from PyRef
602///         let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
603///         // We can get &Self::BaseType by as_ref
604///         let basename = slf.as_ref().basename;
605///         format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
606///     }
607/// }
608/// # Python::with_gil(|py| {
609/// #     let sub = Py::new(py, Child::new()).unwrap();
610/// #     pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()");
611/// # });
612/// ```
613///
614/// See the [module-level documentation](self) for more information.
615#[repr(transparent)]
616pub struct PyRef<'p, T: PyClass> {
617    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
618    // store `Borrowed` here instead, avoiding reference counting overhead.
619    inner: Bound<'p, T>,
620}
621
622impl<'p, T: PyClass> PyRef<'p, T> {
623    /// Returns a `Python` token that is bound to the lifetime of the `PyRef`.
624    pub fn py(&self) -> Python<'p> {
625        self.inner.py()
626    }
627}
628
629impl<'p, T, U> AsRef<U> for PyRef<'p, T>
630where
631    T: PyClass<BaseType = U>,
632    U: PyClass,
633{
634    fn as_ref(&self) -> &T::BaseType {
635        self.as_super()
636    }
637}
638
639impl<'py, T: PyClass> PyRef<'py, T> {
640    /// Returns the raw FFI pointer represented by self.
641    ///
642    /// # Safety
643    ///
644    /// Callers are responsible for ensuring that the pointer does not outlive self.
645    ///
646    /// The reference is borrowed; callers should not decrease the reference count
647    /// when they are finished with the pointer.
648    #[inline]
649    pub fn as_ptr(&self) -> *mut ffi::PyObject {
650        self.inner.as_ptr()
651    }
652
653    /// Returns an owned raw FFI pointer represented by self.
654    ///
655    /// # Safety
656    ///
657    /// The reference is owned; when finished the caller should either transfer ownership
658    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
659    #[inline]
660    pub fn into_ptr(self) -> *mut ffi::PyObject {
661        self.inner.clone().into_ptr()
662    }
663
664    #[track_caller]
665    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
666        Self::try_borrow(obj).expect("Already mutably borrowed")
667    }
668
669    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowError> {
670        let cell = obj.get_class_object();
671        cell.ensure_threadsafe();
672        cell.borrow_checker()
673            .try_borrow()
674            .map(|_| Self { inner: obj.clone() })
675    }
676}
677
678impl<'p, T, U> PyRef<'p, T>
679where
680    T: PyClass<BaseType = U>,
681    U: PyClass,
682{
683    /// Gets a `PyRef<T::BaseType>`.
684    ///
685    /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be
686    /// used to get the base of `T::BaseType`.
687    ///
688    /// But with the help of this method, you can get hold of instances of the
689    /// super-superclass when needed.
690    ///
691    /// # Examples
692    /// ```
693    /// # use pyo3::prelude::*;
694    /// #[pyclass(subclass)]
695    /// struct Base1 {
696    ///     name1: &'static str,
697    /// }
698    ///
699    /// #[pyclass(extends=Base1, subclass)]
700    /// struct Base2 {
701    ///     name2: &'static str,
702    /// }
703    ///
704    /// #[pyclass(extends=Base2)]
705    /// struct Sub {
706    ///     name3: &'static str,
707    /// }
708    ///
709    /// #[pymethods]
710    /// impl Sub {
711    ///     #[new]
712    ///     fn new() -> PyClassInitializer<Self> {
713    ///         PyClassInitializer::from(Base1 { name1: "base1" })
714    ///             .add_subclass(Base2 { name2: "base2" })
715    ///             .add_subclass(Self { name3: "sub" })
716    ///     }
717    ///     fn name(slf: PyRef<'_, Self>) -> String {
718    ///         let subname = slf.name3;
719    ///         let super_ = slf.into_super();
720    ///         format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
721    ///     }
722    /// }
723    /// # Python::with_gil(|py| {
724    /// #     let sub = Py::new(py, Sub::new()).unwrap();
725    /// #     pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
726    /// # });
727    /// ```
728    pub fn into_super(self) -> PyRef<'p, U> {
729        let py = self.py();
730        PyRef {
731            inner: unsafe {
732                ManuallyDrop::new(self)
733                    .as_ptr()
734                    .assume_owned(py)
735                    .downcast_into_unchecked()
736            },
737        }
738    }
739
740    /// Borrows a shared reference to `PyRef<T::BaseType>`.
741    ///
742    /// With the help of this method, you can access attributes and call methods
743    /// on the superclass without consuming the `PyRef<T>`. This method can also
744    /// be chained to access the super-superclass (and so on).
745    ///
746    /// # Examples
747    /// ```
748    /// # use pyo3::prelude::*;
749    /// #[pyclass(subclass)]
750    /// struct Base {
751    ///     base_name: &'static str,
752    /// }
753    /// #[pymethods]
754    /// impl Base {
755    ///     fn base_name_len(&self) -> usize {
756    ///         self.base_name.len()
757    ///     }
758    /// }
759    ///
760    /// #[pyclass(extends=Base)]
761    /// struct Sub {
762    ///     sub_name: &'static str,
763    /// }
764    ///
765    /// #[pymethods]
766    /// impl Sub {
767    ///     #[new]
768    ///     fn new() -> (Self, Base) {
769    ///         (Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
770    ///     }
771    ///     fn sub_name_len(&self) -> usize {
772    ///         self.sub_name.len()
773    ///     }
774    ///     fn format_name_lengths(slf: PyRef<'_, Self>) -> String {
775    ///         format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
776    ///     }
777    /// }
778    /// # Python::with_gil(|py| {
779    /// #     let sub = Py::new(py, Sub::new()).unwrap();
780    /// #     pyo3::py_run!(py, sub, "assert sub.format_name_lengths() == '9 8'")
781    /// # });
782    /// ```
783    pub fn as_super(&self) -> &PyRef<'p, U> {
784        let ptr = ptr_from_ref::<Bound<'p, T>>(&self.inner)
785            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
786            .cast::<Bound<'p, T::BaseType>>()
787            // `Bound<T::BaseType>` has the same layout as `PyRef<T::BaseType>`
788            .cast::<PyRef<'p, T::BaseType>>();
789        unsafe { &*ptr }
790    }
791}
792
793impl<'p, T: PyClass> Deref for PyRef<'p, T> {
794    type Target = T;
795
796    #[inline]
797    fn deref(&self) -> &T {
798        unsafe { &*self.inner.get_class_object().get_ptr() }
799    }
800}
801
802impl<'p, T: PyClass> Drop for PyRef<'p, T> {
803    fn drop(&mut self) {
804        self.inner
805            .get_class_object()
806            .borrow_checker()
807            .release_borrow()
808    }
809}
810
811impl<T: PyClass> IntoPy<PyObject> for PyRef<'_, T> {
812    fn into_py(self, py: Python<'_>) -> PyObject {
813        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
814    }
815}
816
817impl<T: PyClass> IntoPy<PyObject> for &'_ PyRef<'_, T> {
818    fn into_py(self, py: Python<'_>) -> PyObject {
819        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
820    }
821}
822
823#[cfg(feature = "gil-refs")]
824#[allow(deprecated)]
825impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRef<'a, T> {
826    type Error = PyBorrowError;
827    fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
828        cell.try_borrow()
829    }
830}
831
832unsafe impl<'a, T: PyClass> AsPyPointer for PyRef<'a, T> {
833    fn as_ptr(&self) -> *mut ffi::PyObject {
834        self.inner.as_ptr()
835    }
836}
837
838impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
839    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
840        fmt::Debug::fmt(&**self, f)
841    }
842}
843
844/// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`].
845///
846/// See the [module-level documentation](self) for more information.
847#[repr(transparent)]
848pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
849    // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
850    // store `Borrowed` here instead, avoiding reference counting overhead.
851    inner: Bound<'p, T>,
852}
853
854impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
855    /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
856    pub fn py(&self) -> Python<'p> {
857        self.inner.py()
858    }
859}
860
861impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
862where
863    T: PyClass<BaseType = U, Frozen = False>,
864    U: PyClass<Frozen = False>,
865{
866    fn as_ref(&self) -> &T::BaseType {
867        PyRefMut::downgrade(self).as_super()
868    }
869}
870
871impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
872where
873    T: PyClass<BaseType = U, Frozen = False>,
874    U: PyClass<Frozen = False>,
875{
876    fn as_mut(&mut self) -> &mut T::BaseType {
877        self.as_super()
878    }
879}
880
881impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> {
882    /// Returns the raw FFI pointer represented by self.
883    ///
884    /// # Safety
885    ///
886    /// Callers are responsible for ensuring that the pointer does not outlive self.
887    ///
888    /// The reference is borrowed; callers should not decrease the reference count
889    /// when they are finished with the pointer.
890    #[inline]
891    pub fn as_ptr(&self) -> *mut ffi::PyObject {
892        self.inner.as_ptr()
893    }
894
895    /// Returns an owned raw FFI pointer represented by self.
896    ///
897    /// # Safety
898    ///
899    /// The reference is owned; when finished the caller should either transfer ownership
900    /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
901    #[inline]
902    pub fn into_ptr(self) -> *mut ffi::PyObject {
903        self.inner.clone().into_ptr()
904    }
905
906    #[inline]
907    #[track_caller]
908    pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
909        Self::try_borrow(obj).expect("Already borrowed")
910    }
911
912    pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
913        let cell = obj.get_class_object();
914        cell.ensure_threadsafe();
915        cell.borrow_checker()
916            .try_borrow_mut()
917            .map(|_| Self { inner: obj.clone() })
918    }
919
920    pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
921        // `PyRefMut<T>` and `PyRef<T>` have the same layout
922        unsafe { &*ptr_from_ref(slf).cast() }
923    }
924}
925
926impl<'p, T, U> PyRefMut<'p, T>
927where
928    T: PyClass<BaseType = U, Frozen = False>,
929    U: PyClass<Frozen = False>,
930{
931    /// Gets a `PyRef<T::BaseType>`.
932    ///
933    /// See [`PyRef::into_super`] for more.
934    pub fn into_super(self) -> PyRefMut<'p, U> {
935        let py = self.py();
936        PyRefMut {
937            inner: unsafe {
938                ManuallyDrop::new(self)
939                    .as_ptr()
940                    .assume_owned(py)
941                    .downcast_into_unchecked()
942            },
943        }
944    }
945
946    /// Borrows a mutable reference to `PyRefMut<T::BaseType>`.
947    ///
948    /// With the help of this method, you can mutate attributes and call mutating
949    /// methods on the superclass without consuming the `PyRefMut<T>`. This method
950    /// can also be chained to access the super-superclass (and so on).
951    ///
952    /// See [`PyRef::as_super`] for more.
953    pub fn as_super(&mut self) -> &mut PyRefMut<'p, U> {
954        let ptr = ptr_from_mut::<Bound<'p, T>>(&mut self.inner)
955            // `Bound<T>` has the same layout as `Bound<T::BaseType>`
956            .cast::<Bound<'p, T::BaseType>>()
957            // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`,
958            // and the mutable borrow on `self` prevents aliasing
959            .cast::<PyRefMut<'p, T::BaseType>>();
960        unsafe { &mut *ptr }
961    }
962}
963
964impl<'p, T: PyClass<Frozen = False>> Deref for PyRefMut<'p, T> {
965    type Target = T;
966
967    #[inline]
968    fn deref(&self) -> &T {
969        unsafe { &*self.inner.get_class_object().get_ptr() }
970    }
971}
972
973impl<'p, T: PyClass<Frozen = False>> DerefMut for PyRefMut<'p, T> {
974    #[inline]
975    fn deref_mut(&mut self) -> &mut T {
976        unsafe { &mut *self.inner.get_class_object().get_ptr() }
977    }
978}
979
980impl<'p, T: PyClass<Frozen = False>> Drop for PyRefMut<'p, T> {
981    fn drop(&mut self) {
982        self.inner
983            .get_class_object()
984            .borrow_checker()
985            .release_borrow_mut()
986    }
987}
988
989impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for PyRefMut<'_, T> {
990    fn into_py(self, py: Python<'_>) -> PyObject {
991        unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
992    }
993}
994
995impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for &'_ PyRefMut<'_, T> {
996    fn into_py(self, py: Python<'_>) -> PyObject {
997        self.inner.clone().into_py(py)
998    }
999}
1000
1001unsafe impl<'a, T: PyClass<Frozen = False>> AsPyPointer for PyRefMut<'a, T> {
1002    fn as_ptr(&self) -> *mut ffi::PyObject {
1003        self.inner.as_ptr()
1004    }
1005}
1006
1007#[cfg(feature = "gil-refs")]
1008#[allow(deprecated)]
1009impl<'a, T: PyClass<Frozen = False>> std::convert::TryFrom<&'a PyCell<T>>
1010    for crate::PyRefMut<'a, T>
1011{
1012    type Error = PyBorrowMutError;
1013    fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
1014        cell.try_borrow_mut()
1015    }
1016}
1017
1018impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
1019    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1020        fmt::Debug::fmt(self.deref(), f)
1021    }
1022}
1023
1024/// An error type returned by [`Bound::try_borrow`].
1025///
1026/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
1027pub struct PyBorrowError {
1028    _private: (),
1029}
1030
1031impl fmt::Debug for PyBorrowError {
1032    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1033        f.debug_struct("PyBorrowError").finish()
1034    }
1035}
1036
1037impl fmt::Display for PyBorrowError {
1038    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1039        fmt::Display::fmt("Already mutably borrowed", f)
1040    }
1041}
1042
1043impl From<PyBorrowError> for PyErr {
1044    fn from(other: PyBorrowError) -> Self {
1045        PyRuntimeError::new_err(other.to_string())
1046    }
1047}
1048
1049/// An error type returned by [`Bound::try_borrow_mut`].
1050///
1051/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
1052pub struct PyBorrowMutError {
1053    _private: (),
1054}
1055
1056impl fmt::Debug for PyBorrowMutError {
1057    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1058        f.debug_struct("PyBorrowMutError").finish()
1059    }
1060}
1061
1062impl fmt::Display for PyBorrowMutError {
1063    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1064        fmt::Display::fmt("Already borrowed", f)
1065    }
1066}
1067
1068impl From<PyBorrowMutError> for PyErr {
1069    fn from(other: PyBorrowMutError) -> Self {
1070        PyRuntimeError::new_err(other.to_string())
1071    }
1072}
1073
1074#[cfg(test)]
1075#[cfg(feature = "macros")]
1076mod tests {
1077
1078    use super::*;
1079
1080    #[crate::pyclass]
1081    #[pyo3(crate = "crate")]
1082    #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1083    struct SomeClass(i32);
1084
1085    #[cfg(feature = "gil-refs")]
1086    mod deprecated {
1087        use super::*;
1088
1089        #[test]
1090        fn pycell_replace() {
1091            Python::with_gil(|py| {
1092                #[allow(deprecated)]
1093                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1094                assert_eq!(*cell.borrow(), SomeClass(0));
1095
1096                let previous = cell.replace(SomeClass(123));
1097                assert_eq!(previous, SomeClass(0));
1098                assert_eq!(*cell.borrow(), SomeClass(123));
1099            })
1100        }
1101
1102        #[test]
1103        #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1104        fn pycell_replace_panic() {
1105            Python::with_gil(|py| {
1106                #[allow(deprecated)]
1107                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1108                let _guard = cell.borrow();
1109
1110                cell.replace(SomeClass(123));
1111            })
1112        }
1113
1114        #[test]
1115        fn pycell_replace_with() {
1116            Python::with_gil(|py| {
1117                #[allow(deprecated)]
1118                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1119                assert_eq!(*cell.borrow(), SomeClass(0));
1120
1121                let previous = cell.replace_with(|value| {
1122                    *value = SomeClass(2);
1123                    SomeClass(123)
1124                });
1125                assert_eq!(previous, SomeClass(2));
1126                assert_eq!(*cell.borrow(), SomeClass(123));
1127            })
1128        }
1129
1130        #[test]
1131        #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1132        fn pycell_replace_with_panic() {
1133            Python::with_gil(|py| {
1134                #[allow(deprecated)]
1135                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1136                let _guard = cell.borrow();
1137
1138                cell.replace_with(|_| SomeClass(123));
1139            })
1140        }
1141
1142        #[test]
1143        fn pycell_swap() {
1144            Python::with_gil(|py| {
1145                #[allow(deprecated)]
1146                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1147                #[allow(deprecated)]
1148                let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1149                assert_eq!(*cell.borrow(), SomeClass(0));
1150                assert_eq!(*cell2.borrow(), SomeClass(123));
1151
1152                cell.swap(cell2);
1153                assert_eq!(*cell.borrow(), SomeClass(123));
1154                assert_eq!(*cell2.borrow(), SomeClass(0));
1155            })
1156        }
1157
1158        #[test]
1159        #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1160        fn pycell_swap_panic() {
1161            Python::with_gil(|py| {
1162                #[allow(deprecated)]
1163                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1164                #[allow(deprecated)]
1165                let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1166
1167                let _guard = cell.borrow();
1168                cell.swap(cell2);
1169            })
1170        }
1171
1172        #[test]
1173        #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1174        fn pycell_swap_panic_other_borrowed() {
1175            Python::with_gil(|py| {
1176                #[allow(deprecated)]
1177                let cell = PyCell::new(py, SomeClass(0)).unwrap();
1178                #[allow(deprecated)]
1179                let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1180
1181                let _guard = cell2.borrow();
1182                cell.swap(cell2);
1183            })
1184        }
1185    }
1186
1187    #[test]
1188    fn test_as_ptr() {
1189        Python::with_gil(|py| {
1190            let cell = Bound::new(py, SomeClass(0)).unwrap();
1191            let ptr = cell.as_ptr();
1192
1193            assert_eq!(cell.borrow().as_ptr(), ptr);
1194            assert_eq!(cell.borrow_mut().as_ptr(), ptr);
1195        })
1196    }
1197
1198    #[test]
1199    fn test_into_ptr() {
1200        Python::with_gil(|py| {
1201            let cell = Bound::new(py, SomeClass(0)).unwrap();
1202            let ptr = cell.as_ptr();
1203
1204            assert_eq!(cell.borrow().into_ptr(), ptr);
1205            unsafe { ffi::Py_DECREF(ptr) };
1206
1207            assert_eq!(cell.borrow_mut().into_ptr(), ptr);
1208            unsafe { ffi::Py_DECREF(ptr) };
1209        })
1210    }
1211
1212    #[crate::pyclass]
1213    #[pyo3(crate = "crate", subclass)]
1214    struct BaseClass {
1215        val1: usize,
1216    }
1217
1218    #[crate::pyclass]
1219    #[pyo3(crate = "crate", extends=BaseClass, subclass)]
1220    struct SubClass {
1221        val2: usize,
1222    }
1223
1224    #[crate::pyclass]
1225    #[pyo3(crate = "crate", extends=SubClass)]
1226    struct SubSubClass {
1227        val3: usize,
1228    }
1229
1230    #[crate::pymethods]
1231    #[pyo3(crate = "crate")]
1232    impl SubSubClass {
1233        #[new]
1234        fn new(py: Python<'_>) -> crate::Py<SubSubClass> {
1235            let init = crate::PyClassInitializer::from(BaseClass { val1: 10 })
1236                .add_subclass(SubClass { val2: 15 })
1237                .add_subclass(SubSubClass { val3: 20 });
1238            crate::Py::new(py, init).expect("allocation error")
1239        }
1240
1241        fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) {
1242            let val1 = self_.as_super().as_super().val1;
1243            let val2 = self_.as_super().val2;
1244            (val1, val2, self_.val3)
1245        }
1246
1247        fn double_values(mut self_: PyRefMut<'_, Self>) {
1248            self_.as_super().as_super().val1 *= 2;
1249            self_.as_super().val2 *= 2;
1250            self_.val3 *= 2;
1251        }
1252    }
1253
1254    #[test]
1255    fn test_pyref_as_super() {
1256        Python::with_gil(|py| {
1257            let obj = SubSubClass::new(py).into_bound(py);
1258            let pyref = obj.borrow();
1259            assert_eq!(pyref.as_super().as_super().val1, 10);
1260            assert_eq!(pyref.as_super().val2, 15);
1261            assert_eq!(pyref.as_ref().val2, 15); // `as_ref` also works
1262            assert_eq!(pyref.val3, 20);
1263            assert_eq!(SubSubClass::get_values(pyref), (10, 15, 20));
1264        });
1265    }
1266
1267    #[test]
1268    fn test_pyrefmut_as_super() {
1269        Python::with_gil(|py| {
1270            let obj = SubSubClass::new(py).into_bound(py);
1271            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 15, 20));
1272            {
1273                let mut pyrefmut = obj.borrow_mut();
1274                assert_eq!(pyrefmut.as_super().as_ref().val1, 10);
1275                pyrefmut.as_super().as_super().val1 -= 5;
1276                pyrefmut.as_super().val2 -= 3;
1277                pyrefmut.as_mut().val2 -= 2; // `as_mut` also works
1278                pyrefmut.val3 -= 5;
1279            }
1280            assert_eq!(SubSubClass::get_values(obj.borrow()), (5, 10, 15));
1281            SubSubClass::double_values(obj.borrow_mut());
1282            assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 20, 30));
1283        });
1284    }
1285
1286    #[test]
1287    fn test_pyrefs_in_python() {
1288        Python::with_gil(|py| {
1289            let obj = SubSubClass::new(py);
1290            crate::py_run!(py, obj, "assert obj.get_values() == (10, 15, 20)");
1291            crate::py_run!(py, obj, "assert obj.double_values() is None");
1292            crate::py_run!(py, obj, "assert obj.get_values() == (20, 30, 40)");
1293        });
1294    }
1295}