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::internal_tricks::{ptr_from_mut, ptr_from_ref};
200use crate::pyclass::{boolean_struct::False, PyClass};
201use crate::{ffi, Borrowed, Bound, PyErr, Python};
202use std::convert::Infallible;
203use std::fmt;
204use std::mem::ManuallyDrop;
205use std::ops::{Deref, DerefMut};
206
207pub(crate) mod impl_;
208use impl_::{PyClassBorrowChecker, PyClassObjectLayout};
209
210/// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`].
211///
212/// See the [`Bound`] documentation for more information.
213///
214/// # Examples
215///
216/// You can use [`PyRef`] as an alternative to a `&self` receiver when
217/// - you need to access the pointer of the [`Bound`], or
218/// - you want to get a super class.
219/// ```
220/// # use pyo3::prelude::*;
221/// #[pyclass(subclass)]
222/// struct Parent {
223/// basename: &'static str,
224/// }
225///
226/// #[pyclass(extends=Parent)]
227/// struct Child {
228/// name: &'static str,
229/// }
230///
231/// #[pymethods]
232/// impl Child {
233/// #[new]
234/// fn new() -> (Self, Parent) {
235/// (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
236/// }
237///
238/// fn format(slf: PyRef<'_, Self>) -> String {
239/// // We can get *mut ffi::PyObject from PyRef
240/// let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
241/// // We can get &Self::BaseType by as_ref
242/// let basename = slf.as_ref().basename;
243/// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
244/// }
245/// }
246/// # Python::attach(|py| {
247/// # let sub = Py::new(py, Child::new()).unwrap();
248/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()");
249/// # });
250/// ```
251///
252/// See the [module-level documentation](self) for more information.
253#[repr(transparent)]
254pub struct PyRef<'p, T: PyClass> {
255 // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
256 // store `Borrowed` here instead, avoiding reference counting overhead.
257 inner: Bound<'p, T>,
258}
259
260impl<'p, T: PyClass> PyRef<'p, T> {
261 /// Returns a `Python` token that is bound to the lifetime of the `PyRef`.
262 pub fn py(&self) -> Python<'p> {
263 self.inner.py()
264 }
265}
266
267impl<T, U> AsRef<U> for PyRef<'_, T>
268where
269 T: PyClass<BaseType = U>,
270 U: PyClass,
271{
272 fn as_ref(&self) -> &T::BaseType {
273 self.as_super()
274 }
275}
276
277impl<'py, T: PyClass> PyRef<'py, T> {
278 /// Returns the raw FFI pointer represented by self.
279 ///
280 /// # Safety
281 ///
282 /// Callers are responsible for ensuring that the pointer does not outlive self.
283 ///
284 /// The reference is borrowed; callers should not decrease the reference count
285 /// when they are finished with the pointer.
286 #[inline]
287 pub fn as_ptr(&self) -> *mut ffi::PyObject {
288 self.inner.as_ptr()
289 }
290
291 /// Returns an owned raw FFI pointer represented by self.
292 ///
293 /// # Safety
294 ///
295 /// The reference is owned; when finished the caller should either transfer ownership
296 /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
297 #[inline]
298 pub fn into_ptr(self) -> *mut ffi::PyObject {
299 self.inner.clone().into_ptr()
300 }
301
302 #[track_caller]
303 pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
304 Self::try_borrow(obj).expect("Already mutably borrowed")
305 }
306
307 pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowError> {
308 let cell = obj.get_class_object();
309 cell.ensure_threadsafe();
310 cell.borrow_checker()
311 .try_borrow()
312 .map(|_| Self { inner: obj.clone() })
313 }
314}
315
316impl<'p, T, U> PyRef<'p, T>
317where
318 T: PyClass<BaseType = U>,
319 U: PyClass,
320{
321 /// Gets a `PyRef<T::BaseType>`.
322 ///
323 /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be
324 /// used to get the base of `T::BaseType`.
325 ///
326 /// But with the help of this method, you can get hold of instances of the
327 /// super-superclass when needed.
328 ///
329 /// # Examples
330 /// ```
331 /// # use pyo3::prelude::*;
332 /// #[pyclass(subclass)]
333 /// struct Base1 {
334 /// name1: &'static str,
335 /// }
336 ///
337 /// #[pyclass(extends=Base1, subclass)]
338 /// struct Base2 {
339 /// name2: &'static str,
340 /// }
341 ///
342 /// #[pyclass(extends=Base2)]
343 /// struct Sub {
344 /// name3: &'static str,
345 /// }
346 ///
347 /// #[pymethods]
348 /// impl Sub {
349 /// #[new]
350 /// fn new() -> PyClassInitializer<Self> {
351 /// PyClassInitializer::from(Base1 { name1: "base1" })
352 /// .add_subclass(Base2 { name2: "base2" })
353 /// .add_subclass(Self { name3: "sub" })
354 /// }
355 /// fn name(slf: PyRef<'_, Self>) -> String {
356 /// let subname = slf.name3;
357 /// let super_ = slf.into_super();
358 /// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
359 /// }
360 /// }
361 /// # Python::attach(|py| {
362 /// # let sub = Py::new(py, Sub::new()).unwrap();
363 /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
364 /// # });
365 /// ```
366 pub fn into_super(self) -> PyRef<'p, U> {
367 let py = self.py();
368 let t_not_frozen = !<T::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;
369 let u_frozen = <U::Frozen as crate::pyclass::boolean_struct::private::Boolean>::VALUE;
370 if t_not_frozen && u_frozen {
371 // If `T` is mutable subclass of `U` differ, then it is possible that we need to
372 // release the borrow count now. (e.g. `U` may have a noop borrow checker so
373 // dropping the `PyRef<U>` later would noop and leak the borrow we currently hold.)
374 //
375 // However it's nontrivial, if `U` itself has a mutable base class `V`,
376 // then the borrow checker of both `T` and `U` is the shared borrow checker of `V`.
377 //
378 // But it's really hard to prove that in the type system, the soundest thing we
379 // can do is just add a borrow to `U` now and then release the borrow of `T`.
380
381 self.inner
382 .as_super()
383 .get_class_object()
384 .borrow_checker()
385 .try_borrow()
386 .expect("this object is already borrowed");
387
388 self.inner
389 .get_class_object()
390 .borrow_checker()
391 .release_borrow()
392 };
393 PyRef {
394 inner: unsafe {
395 ManuallyDrop::new(self)
396 .as_ptr()
397 .assume_owned_unchecked(py)
398 .cast_into_unchecked()
399 },
400 }
401 }
402
403 /// Borrows a shared reference to `PyRef<T::BaseType>`.
404 ///
405 /// With the help of this method, you can access attributes and call methods
406 /// on the superclass without consuming the `PyRef<T>`. This method can also
407 /// be chained to access the super-superclass (and so on).
408 ///
409 /// # Examples
410 /// ```
411 /// # use pyo3::prelude::*;
412 /// #[pyclass(subclass)]
413 /// struct Base {
414 /// base_name: &'static str,
415 /// }
416 /// #[pymethods]
417 /// impl Base {
418 /// fn base_name_len(&self) -> usize {
419 /// self.base_name.len()
420 /// }
421 /// }
422 ///
423 /// #[pyclass(extends=Base)]
424 /// struct Sub {
425 /// sub_name: &'static str,
426 /// }
427 ///
428 /// #[pymethods]
429 /// impl Sub {
430 /// #[new]
431 /// fn new() -> (Self, Base) {
432 /// (Self { sub_name: "sub_name" }, Base { base_name: "base_name" })
433 /// }
434 /// fn sub_name_len(&self) -> usize {
435 /// self.sub_name.len()
436 /// }
437 /// fn format_name_lengths(slf: PyRef<'_, Self>) -> String {
438 /// format!("{} {}", slf.as_super().base_name_len(), slf.sub_name_len())
439 /// }
440 /// }
441 /// # Python::attach(|py| {
442 /// # let sub = Py::new(py, Sub::new()).unwrap();
443 /// # pyo3::py_run!(py, sub, "assert sub.format_name_lengths() == '9 8'")
444 /// # });
445 /// ```
446 pub fn as_super(&self) -> &PyRef<'p, U> {
447 let ptr = ptr_from_ref::<Bound<'p, T>>(&self.inner)
448 // `Bound<T>` has the same layout as `Bound<T::BaseType>`
449 .cast::<Bound<'p, T::BaseType>>()
450 // `Bound<T::BaseType>` has the same layout as `PyRef<T::BaseType>`
451 .cast::<PyRef<'p, T::BaseType>>();
452 unsafe { &*ptr }
453 }
454}
455
456impl<T: PyClass> Deref for PyRef<'_, T> {
457 type Target = T;
458
459 #[inline]
460 fn deref(&self) -> &T {
461 unsafe { &*self.inner.get_class_object().get_ptr() }
462 }
463}
464
465impl<T: PyClass> Drop for PyRef<'_, T> {
466 fn drop(&mut self) {
467 self.inner
468 .get_class_object()
469 .borrow_checker()
470 .release_borrow()
471 }
472}
473
474impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> {
475 type Target = T;
476 type Output = Bound<'py, T>;
477 type Error = Infallible;
478
479 #[cfg(feature = "experimental-inspect")]
480 const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE;
481
482 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
483 Ok(self.inner.clone())
484 }
485}
486
487impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> {
488 type Target = T;
489 type Output = Borrowed<'a, 'py, T>;
490 type Error = Infallible;
491
492 #[cfg(feature = "experimental-inspect")]
493 const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE;
494
495 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
496 Ok(self.inner.as_borrowed())
497 }
498}
499
500impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
501 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
502 fmt::Debug::fmt(&**self, f)
503 }
504}
505
506/// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`].
507///
508/// See the [module-level documentation](self) for more information.
509#[repr(transparent)]
510pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
511 // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to
512 // store `Borrowed` here instead, avoiding reference counting overhead.
513 inner: Bound<'p, T>,
514}
515
516impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
517 /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
518 pub fn py(&self) -> Python<'p> {
519 self.inner.py()
520 }
521}
522
523impl<T, U> AsRef<U> for PyRefMut<'_, T>
524where
525 T: PyClass<BaseType = U, Frozen = False>,
526 U: PyClass<Frozen = False>,
527{
528 fn as_ref(&self) -> &T::BaseType {
529 PyRefMut::downgrade(self).as_super()
530 }
531}
532
533impl<T, U> AsMut<U> for PyRefMut<'_, T>
534where
535 T: PyClass<BaseType = U, Frozen = False>,
536 U: PyClass<Frozen = False>,
537{
538 fn as_mut(&mut self) -> &mut T::BaseType {
539 self.as_super()
540 }
541}
542
543impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> {
544 /// Returns the raw FFI pointer represented by self.
545 ///
546 /// # Safety
547 ///
548 /// Callers are responsible for ensuring that the pointer does not outlive self.
549 ///
550 /// The reference is borrowed; callers should not decrease the reference count
551 /// when they are finished with the pointer.
552 #[inline]
553 pub fn as_ptr(&self) -> *mut ffi::PyObject {
554 self.inner.as_ptr()
555 }
556
557 /// Returns an owned raw FFI pointer represented by self.
558 ///
559 /// # Safety
560 ///
561 /// The reference is owned; when finished the caller should either transfer ownership
562 /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
563 #[inline]
564 pub fn into_ptr(self) -> *mut ffi::PyObject {
565 self.inner.clone().into_ptr()
566 }
567
568 #[inline]
569 #[track_caller]
570 pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self {
571 Self::try_borrow(obj).expect("Already borrowed")
572 }
573
574 pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> {
575 let cell = obj.get_class_object();
576 cell.ensure_threadsafe();
577 cell.borrow_checker()
578 .try_borrow_mut()
579 .map(|_| Self { inner: obj.clone() })
580 }
581
582 pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> {
583 // `PyRefMut<T>` and `PyRef<T>` have the same layout
584 unsafe { &*ptr_from_ref(slf).cast() }
585 }
586}
587
588impl<'p, T, U> PyRefMut<'p, T>
589where
590 T: PyClass<BaseType = U, Frozen = False>,
591 U: PyClass<Frozen = False>,
592{
593 /// Gets a `PyRef<T::BaseType>`.
594 ///
595 /// See [`PyRef::into_super`] for more.
596 pub fn into_super(self) -> PyRefMut<'p, U> {
597 let py = self.py();
598 PyRefMut {
599 inner: unsafe {
600 ManuallyDrop::new(self)
601 .as_ptr()
602 .assume_owned_unchecked(py)
603 .cast_into_unchecked()
604 },
605 }
606 }
607
608 /// Borrows a mutable reference to `PyRefMut<T::BaseType>`.
609 ///
610 /// With the help of this method, you can mutate attributes and call mutating
611 /// methods on the superclass without consuming the `PyRefMut<T>`. This method
612 /// can also be chained to access the super-superclass (and so on).
613 ///
614 /// See [`PyRef::as_super`] for more.
615 pub fn as_super(&mut self) -> &mut PyRefMut<'p, U> {
616 let ptr = ptr_from_mut::<Bound<'p, T>>(&mut self.inner)
617 // `Bound<T>` has the same layout as `Bound<T::BaseType>`
618 .cast::<Bound<'p, T::BaseType>>()
619 // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`,
620 // and the mutable borrow on `self` prevents aliasing
621 .cast::<PyRefMut<'p, T::BaseType>>();
622 unsafe { &mut *ptr }
623 }
624}
625
626impl<T: PyClass<Frozen = False>> Deref for PyRefMut<'_, T> {
627 type Target = T;
628
629 #[inline]
630 fn deref(&self) -> &T {
631 unsafe { &*self.inner.get_class_object().get_ptr() }
632 }
633}
634
635impl<T: PyClass<Frozen = False>> DerefMut for PyRefMut<'_, T> {
636 #[inline]
637 fn deref_mut(&mut self) -> &mut T {
638 unsafe { &mut *self.inner.get_class_object().get_ptr() }
639 }
640}
641
642impl<T: PyClass<Frozen = False>> Drop for PyRefMut<'_, T> {
643 fn drop(&mut self) {
644 self.inner
645 .get_class_object()
646 .borrow_checker()
647 .release_borrow_mut()
648 }
649}
650
651impl<'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for PyRefMut<'py, T> {
652 type Target = T;
653 type Output = Bound<'py, T>;
654 type Error = Infallible;
655
656 #[cfg(feature = "experimental-inspect")]
657 const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE;
658
659 fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
660 Ok(self.inner.clone())
661 }
662}
663
664impl<'a, 'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for &'a PyRefMut<'py, T> {
665 type Target = T;
666 type Output = Borrowed<'a, 'py, T>;
667 type Error = Infallible;
668
669 #[cfg(feature = "experimental-inspect")]
670 const OUTPUT_TYPE: &'static str = T::PYTHON_TYPE;
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::attach(|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::attach(|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::attach(|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::attach(|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::attach(|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
853 #[test]
854 fn test_into_frozen_super_released_borrow() {
855 #[crate::pyclass]
856 #[pyo3(crate = "crate", subclass, frozen)]
857 struct BaseClass {}
858
859 #[crate::pyclass]
860 #[pyo3(crate = "crate", extends=BaseClass, subclass)]
861 struct SubClass {}
862
863 #[crate::pymethods]
864 #[pyo3(crate = "crate")]
865 impl SubClass {
866 #[new]
867 fn new(py: Python<'_>) -> Bound<'_, SubClass> {
868 let init = crate::PyClassInitializer::from(BaseClass {}).add_subclass(SubClass {});
869 Bound::new(py, init).expect("allocation error")
870 }
871 }
872
873 Python::attach(|py| {
874 let obj = SubClass::new(py);
875 drop(obj.borrow().into_super());
876 assert!(obj.try_borrow_mut().is_ok());
877 })
878 }
879
880 #[test]
881 fn test_into_frozen_super_mutable_base_holds_borrow() {
882 #[crate::pyclass]
883 #[pyo3(crate = "crate", subclass)]
884 struct BaseClass {}
885
886 #[crate::pyclass]
887 #[pyo3(crate = "crate", extends=BaseClass, subclass, frozen)]
888 struct SubClass {}
889
890 #[crate::pyclass]
891 #[pyo3(crate = "crate", extends=SubClass, subclass)]
892 struct SubSubClass {}
893
894 #[crate::pymethods]
895 #[pyo3(crate = "crate")]
896 impl SubSubClass {
897 #[new]
898 fn new(py: Python<'_>) -> Bound<'_, SubSubClass> {
899 let init = crate::PyClassInitializer::from(BaseClass {})
900 .add_subclass(SubClass {})
901 .add_subclass(SubSubClass {});
902 Bound::new(py, init).expect("allocation error")
903 }
904 }
905
906 Python::attach(|py| {
907 let obj = SubSubClass::new(py);
908 let _super_borrow = obj.borrow().into_super();
909 // the whole object still has an immutable borrow, so we cannot
910 // borrow any part mutably (the borrowflag is shared)
911 assert!(obj.try_borrow_mut().is_err());
912 })
913 }
914}