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::TypeHint;
210use impl_::{PyClassBorrowChecker, 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: TypeHint = 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: TypeHint = 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
509/// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`].
510///
511/// See the [module-level documentation](self) for more information.
512#[repr(transparent)]
513pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
514 // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
515 // store `Borrowed` here instead, avoiding reference counting overhead.
516 inner: Bound<'p, T>,
517}
518
519impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
520 /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
521 pub fn py(&self) -> Python<'p> {
522 self.inner.py()
523 }
524}
525
526impl<T> AsRef<T::BaseType> for PyRefMut<'_, T>
527where
528 T: PyClass<Frozen = False>,
529 T::BaseType: PyClass<Frozen = False>,
530{
531 fn as_ref(&self) -> &T::BaseType {
532 PyRefMut::downgrade(self).as_super()
533 }
534}
535
536impl<T> AsMut<T::BaseType> for PyRefMut<'_, T>
537where
538 T: PyClass<Frozen = False>,
539 T::BaseType: PyClass<Frozen = False>,
540{
541 fn as_mut(&mut self) -> &mut T::BaseType {
542 self.as_super()
543 }
544}
545
546impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> {
547 /// Returns the raw FFI pointer represented by self.
548 ///
549 /// # Safety
550 ///
551 /// Callers are responsible for ensuring that the pointer does not outlive self.
552 ///
553 /// The reference is borrowed; callers should not decrease the reference count
554 /// when they are finished with the pointer.
555 #[inline]
556 pub fn as_ptr(&self) -> *mut ffi::PyObject {
557 self.inner.as_ptr()
558 }
559
560 /// Returns an owned raw FFI pointer represented by self.
561 ///
562 /// # Safety
563 ///
564 /// The reference is owned; when finished the caller should either transfer ownership
565 /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
566 #[inline]
567 pub fn into_ptr(self) -> *mut ffi::PyObject {
568 self.inner.clone().into_ptr()
569 }
570
571 #[inline]
572 #[track_caller]
573 pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
574 Self::try_borrow(obj).expect("Already borrowed")
575 }
576
577 pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
578 let cell = obj.get_class_object();
579 cell.ensure_threadsafe();
580 cell.borrow_checker()
581 .try_borrow_mut()
582 .map(|_| Self { inner: obj.clone() })
583 }
584
585 pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
586 let ptr = NonNull::from(slf).cast();
587 // SAFETY: `PyRefMut<T>` and `PyRef<T>` have the same layout
588 unsafe { ptr.as_ref() }
589 }
590}
591
592impl<'p, T> PyRefMut<'p, T>
593where
594 T: PyClass<Frozen = False>,
595 T::BaseType: PyClass<Frozen = False>,
596{
597 /// Gets a `PyRef<T::BaseType>`.
598 ///
599 /// See [`PyRef::into_super`] for more.
600 pub fn into_super(self) -> PyRefMut<'p, T::BaseType> {
601 let py = self.py();
602 PyRefMut {
603 inner: unsafe {
604 ManuallyDrop::new(self)
605 .as_ptr()
606 .assume_owned_unchecked(py)
607 .cast_into_unchecked()
608 },
609 }
610 }
611
612 /// Borrows a mutable reference to `PyRefMut<T::BaseType>`.
613 ///
614 /// With the help of this method, you can mutate attributes and call mutating
615 /// methods on the superclass without consuming the `PyRefMut<T>`. This method
616 /// can also be chained to access the super-superclass (and so on).
617 ///
618 /// See [`PyRef::as_super`] for more.
619 pub fn as_super(&mut self) -> &mut PyRefMut<'p, T::BaseType> {
620 let mut ptr = NonNull::from(&mut self.inner)
621 // `Bound<T>` has the same layout as `Bound<T::BaseType>`
622 .cast::<Bound<'p, T::BaseType>>()
623 // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`,
624 // and the mutable borrow on `self` prevents aliasing
625 .cast::<PyRefMut<'p, T::BaseType>>();
626 // SAFETY: lifetimes are correctly transferred, and `PyRefMut<T>` and `PyRefMut<U>` have the same layout
627 unsafe { ptr.as_mut() }
628 }
629}
630
631impl<T: PyClass<Frozen = False>> Deref for PyRefMut<'_, T> {
632 type Target = T;
633
634 #[inline]
635 fn deref(&self) -> &T {
636 unsafe { &*self.inner.get_class_object().get_ptr() }
637 }
638}
639
640impl<T: PyClass<Frozen = False>> DerefMut for PyRefMut<'_, T> {
641 #[inline]
642 fn deref_mut(&mut self) -> &mut T {
643 unsafe { &mut *self.inner.get_class_object().get_ptr() }
644 }
645}
646
647impl<T: PyClass<Frozen = False>> Drop for PyRefMut<'_, T> {
648 fn drop(&mut self) {
649 self.inner
650 .get_class_object()
651 .borrow_checker()
652 .release_borrow_mut()
653 }
654}
655
656impl<'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for PyRefMut<'py, T> {
657 type Target = T;
658 type Output = Bound<'py, T>;
659 type Error = Infallible;
660
661 #[cfg(feature = "experimental-inspect")]
662 const OUTPUT_TYPE: TypeHint = T::TYPE_HINT;
663
664 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
665 Ok(self.inner.clone())
666 }
667}
668
669impl<'a, 'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for &'a PyRefMut<'py, T> {
670 type Target = T;
671 type Output = Borrowed<'a, 'py, T>;
672 type Error = Infallible;
673
674 #[cfg(feature = "experimental-inspect")]
675 const OUTPUT_TYPE: TypeHint = T::TYPE_HINT;
676
677 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
678 Ok(self.inner.as_borrowed())
679 }
680}
681
682impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
683 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
684 fmt::Debug::fmt(self.deref(), f)
685 }
686}
687
688/// An error type returned by [`Bound::try_borrow`].
689///
690/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
691pub struct PyBorrowError {
692 _private: (),
693}
694
695impl PyBorrowError {
696 pub(crate) fn new() -> Self {
697 Self { _private: () }
698 }
699}
700
701impl fmt::Debug for PyBorrowError {
702 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
703 f.debug_struct("PyBorrowError").finish()
704 }
705}
706
707impl fmt::Display for PyBorrowError {
708 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
709 fmt::Display::fmt("Already mutably borrowed", f)
710 }
711}
712
713impl From<PyBorrowError> for PyErr {
714 fn from(other: PyBorrowError) -> Self {
715 PyRuntimeError::new_err(other.to_string())
716 }
717}
718
719/// An error type returned by [`Bound::try_borrow_mut`].
720///
721/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
722pub struct PyBorrowMutError {
723 _private: (),
724}
725
726impl PyBorrowMutError {
727 pub(crate) fn new() -> Self {
728 Self { _private: () }
729 }
730}
731
732impl fmt::Debug for PyBorrowMutError {
733 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
734 f.debug_struct("PyBorrowMutError").finish()
735 }
736}
737
738impl fmt::Display for PyBorrowMutError {
739 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
740 fmt::Display::fmt("Already borrowed", f)
741 }
742}
743
744impl From<PyBorrowMutError> for PyErr {
745 fn from(other: PyBorrowMutError) -> Self {
746 PyRuntimeError::new_err(other.to_string())
747 }
748}
749
750#[cfg(test)]
751#[cfg(feature = "macros")]
752mod tests {
753
754 use super::*;
755
756 #[crate::pyclass(skip_from_py_object)]
757 #[pyo3(crate = "crate")]
758 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
759 struct SomeClass(i32);
760
761 #[test]
762 fn test_as_ptr() {
763 Python::attach(|py| {
764 let cell = Bound::new(py, SomeClass(0)).unwrap();
765 let ptr = cell.as_ptr();
766
767 assert_eq!(cell.borrow().as_ptr(), ptr);
768 assert_eq!(cell.borrow_mut().as_ptr(), ptr);
769 })
770 }
771
772 #[test]
773 fn test_into_ptr() {
774 Python::attach(|py| {
775 let cell = Bound::new(py, SomeClass(0)).unwrap();
776 let ptr = cell.as_ptr();
777
778 assert_eq!(cell.borrow().into_ptr(), ptr);
779 unsafe { ffi::Py_DECREF(ptr) };
780
781 assert_eq!(cell.borrow_mut().into_ptr(), ptr);
782 unsafe { ffi::Py_DECREF(ptr) };
783 })
784 }
785
786 #[crate::pyclass]
787 #[pyo3(crate = "crate", subclass)]
788 struct BaseClass {
789 val1: usize,
790 }
791
792 #[crate::pyclass]
793 #[pyo3(crate = "crate", extends=BaseClass, subclass)]
794 struct SubClass {
795 val2: usize,
796 }
797
798 #[crate::pyclass]
799 #[pyo3(crate = "crate", extends=SubClass)]
800 struct SubSubClass {
801 val3: usize,
802 }
803
804 #[crate::pymethods]
805 #[pyo3(crate = "crate")]
806 impl SubSubClass {
807 #[new]
808 fn new(py: Python<'_>) -> crate::Py<SubSubClass> {
809 let init = crate::PyClassInitializer::from(BaseClass { val1: 10 })
810 .add_subclass(SubClass { val2: 15 })
811 .add_subclass(SubSubClass { val3: 20 });
812 crate::Py::new(py, init).expect("allocation error")
813 }
814
815 fn get_values(self_: PyRef<'_, Self>) -> (usize, usize, usize) {
816 let val1 = self_.as_super().as_super().val1;
817 let val2 = self_.as_super().val2;
818 (val1, val2, self_.val3)
819 }
820
821 fn double_values(mut self_: PyRefMut<'_, Self>) {
822 self_.as_super().as_super().val1 *= 2;
823 self_.as_super().val2 *= 2;
824 self_.val3 *= 2;
825 }
826 }
827
828 #[test]
829 fn test_pyref_as_super() {
830 Python::attach(|py| {
831 let obj = SubSubClass::new(py).into_bound(py);
832 let pyref = obj.borrow();
833 assert_eq!(pyref.as_super().as_super().val1, 10);
834 assert_eq!(pyref.as_super().val2, 15);
835 assert_eq!(pyref.as_ref().val2, 15); // `as_ref` also works
836 assert_eq!(pyref.val3, 20);
837 assert_eq!(SubSubClass::get_values(pyref), (10, 15, 20));
838 });
839 }
840
841 #[test]
842 fn test_pyrefmut_as_super() {
843 Python::attach(|py| {
844 let obj = SubSubClass::new(py).into_bound(py);
845 assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 15, 20));
846 {
847 let mut pyrefmut = obj.borrow_mut();
848 assert_eq!(pyrefmut.as_super().as_ref().val1, 10);
849 pyrefmut.as_super().as_super().val1 -= 5;
850 pyrefmut.as_super().val2 -= 3;
851 pyrefmut.as_mut().val2 -= 2; // `as_mut` also works
852 pyrefmut.val3 -= 5;
853 }
854 assert_eq!(SubSubClass::get_values(obj.borrow()), (5, 10, 15));
855 SubSubClass::double_values(obj.borrow_mut());
856 assert_eq!(SubSubClass::get_values(obj.borrow()), (10, 20, 30));
857 });
858 }
859
860 #[test]
861 fn test_pyrefs_in_python() {
862 Python::attach(|py| {
863 let obj = SubSubClass::new(py);
864 crate::py_run!(py, obj, "assert obj.get_values() == (10, 15, 20)");
865 crate::py_run!(py, obj, "assert obj.double_values() is None");
866 crate::py_run!(py, obj, "assert obj.get_values() == (20, 30, 40)");
867 });
868 }
869
870 #[test]
871 fn test_into_frozen_super_released_borrow() {
872 #[crate::pyclass]
873 #[pyo3(crate = "crate", subclass, frozen)]
874 struct BaseClass {}
875
876 #[crate::pyclass]
877 #[pyo3(crate = "crate", extends=BaseClass, subclass)]
878 struct SubClass {}
879
880 #[crate::pymethods]
881 #[pyo3(crate = "crate")]
882 impl SubClass {
883 #[new]
884 fn new(py: Python<'_>) -> Bound<'_, SubClass> {
885 let init = crate::PyClassInitializer::from(BaseClass {}).add_subclass(SubClass {});
886 Bound::new(py, init).expect("allocation error")
887 }
888 }
889
890 Python::attach(|py| {
891 let obj = SubClass::new(py);
892 drop(obj.borrow().into_super());
893 assert!(obj.try_borrow_mut().is_ok());
894 })
895 }
896
897 #[test]
898 fn test_into_frozen_super_mutable_base_holds_borrow() {
899 #[crate::pyclass]
900 #[pyo3(crate = "crate", subclass)]
901 struct BaseClass {}
902
903 #[crate::pyclass]
904 #[pyo3(crate = "crate", extends=BaseClass, subclass, frozen)]
905 struct SubClass {}
906
907 #[crate::pyclass]
908 #[pyo3(crate = "crate", extends=SubClass, subclass)]
909 struct SubSubClass {}
910
911 #[crate::pymethods]
912 #[pyo3(crate = "crate")]
913 impl SubSubClass {
914 #[new]
915 fn new(py: Python<'_>) -> Bound<'_, SubSubClass> {
916 let init = crate::PyClassInitializer::from(BaseClass {})
917 .add_subclass(SubClass {})
918 .add_subclass(SubSubClass {});
919 Bound::new(py, init).expect("allocation error")
920 }
921 }
922
923 Python::attach(|py| {
924 let obj = SubSubClass::new(py);
925 let _super_borrow = obj.borrow().into_super();
926 // the whole object still has an immutable borrow, so we cannot
927 // borrow any part mutably (the borrowflag is shared)
928 assert!(obj.try_borrow_mut().is_err());
929 })
930 }
931}