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}