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
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//! let _cell = py
66//! .from_borrowed_ptr::<_pyo3::PyAny>(_slf)
67//! .downcast::<_pyo3::PyCell<Number>>()?;
68//! let mut _ref = _cell.try_borrow_mut()?;
69//! let _slf: &mut Number = &mut *_ref;
70//! _pyo3::callback::convert(py, Number::increment(_slf))
71//! })
72//! }
73//! ```
74//!
75//! # When to use PyCell
76//! ## Using pyclasses from Rust
77//!
78//! However, we *do* need [`PyCell`] if we want to call its methods from Rust:
79//! ```rust
80//! # use pyo3::prelude::*;
81//! #
82//! # #[pyclass]
83//! # struct Number {
84//! # inner: u32,
85//! # }
86//! #
87//! # #[pymethods]
88//! # impl Number {
89//! # fn increment(&mut self) {
90//! # self.inner += 1;
91//! # }
92//! # }
93//! # fn main() -> PyResult<()> {
94//! Python::with_gil(|py| {
95//! let n = Py::new(py, Number { inner: 0 })?;
96//!
97//! // We borrow the guard and then dereference
98//! // it to get a mutable reference to Number
99//! let mut guard: PyRefMut<'_, Number> = n.as_ref(py).borrow_mut();
100//! let n_mutable: &mut Number = &mut *guard;
101//!
102//! n_mutable.increment();
103//!
104//! // To avoid panics we must dispose of the
105//! // `PyRefMut` before borrowing again.
106//! drop(guard);
107//!
108//! let n_immutable: &Number = &n.as_ref(py).borrow();
109//! assert_eq!(n_immutable.inner, 1);
110//!
111//! Ok(())
112//! })
113//! # }
114//! ```
115//! ## Dealing with possibly overlapping mutable references
116//!
117//! It is also necessary to use [`PyCell`] if you can receive mutable arguments that may overlap.
118//! Suppose the following function that swaps the values of two `Number`s:
119//! ```
120//! # use pyo3::prelude::*;
121//! # #[pyclass]
122//! # pub struct Number {
123//! # inner: u32,
124//! # }
125//! #[pyfunction]
126//! fn swap_numbers(a: &mut Number, b: &mut Number) {
127//! std::mem::swap(&mut a.inner, &mut b.inner);
128//! }
129//! # fn main() {
130//! # Python::with_gil(|py| {
131//! # let n = Py::new(py, Number{inner: 35}).unwrap();
132//! # let n2 = n.clone_ref(py);
133//! # assert!(n.is(&n2));
134//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
135//! # fun.call1((n, n2)).expect_err("Managed to create overlapping mutable references. Note: this is undefined behaviour.");
136//! # });
137//! # }
138//! ```
139//! When users pass in the same `Number` as both arguments, one of the mutable borrows will
140//! fail and raise a `RuntimeError`:
141//! ```text
142//! >>> a = Number()
143//! >>> swap_numbers(a, a)
144//! Traceback (most recent call last):
145//! File "<stdin>", line 1, in <module>
146//! RuntimeError: Already borrowed
147//! ```
148//!
149//! It is better to write that function like this:
150//! ```rust
151//! # use pyo3::prelude::*;
152//! # #[pyclass]
153//! # pub struct Number {
154//! # inner: u32,
155//! # }
156//! #[pyfunction]
157//! fn swap_numbers(a: &PyCell<Number>, b: &PyCell<Number>) {
158//! // Check that the pointers are unequal
159//! if !a.is(b) {
160//! std::mem::swap(&mut a.borrow_mut().inner, &mut b.borrow_mut().inner);
161//! } else {
162//! // Do nothing - they are the same object, so don't need swapping.
163//! }
164//! }
165//! # fn main() {
166//! # // With duplicate numbers
167//! # Python::with_gil(|py| {
168//! # let n = Py::new(py, Number{inner: 35}).unwrap();
169//! # let n2 = n.clone_ref(py);
170//! # assert!(n.is(&n2));
171//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
172//! # fun.call1((n, n2)).unwrap();
173//! # });
174//! #
175//! # // With two different numbers
176//! # Python::with_gil(|py| {
177//! # let n = Py::new(py, Number{inner: 35}).unwrap();
178//! # let n2 = Py::new(py, Number{inner: 42}).unwrap();
179//! # assert!(!n.is(&n2));
180//! # let fun = pyo3::wrap_pyfunction!(swap_numbers, py).unwrap();
181//! # fun.call1((&n, &n2)).unwrap();
182//! # let n: u32 = n.borrow(py).inner;
183//! # let n2: u32 = n2.borrow(py).inner;
184//! # assert_eq!(n, 42);
185//! # assert_eq!(n2, 35);
186//! # });
187//! # }
188//! ```
189//! See the [guide] for more information.
190//!
191//! [guide]: https://pyo3.rs/latest/class.html#pycell-and-interior-mutability "PyCell and interior mutability"
192//! [Interior Mutability]: https://doc.rust-lang.org/book/ch15-05-interior-mutability.html "RefCell<T> and the Interior Mutability Pattern - The Rust Programming Language"
193
194use crate::exceptions::PyRuntimeError;
195use crate::impl_::pyclass::{
196 PyClassBaseType, PyClassDict, PyClassImpl, PyClassThreadChecker, PyClassWeakRef,
197};
198use crate::pyclass::{
199 boolean_struct::{False, True},
200 PyClass,
201};
202use crate::pyclass_init::PyClassInitializer;
203use crate::type_object::{PyLayout, PySizedLayout};
204use crate::types::PyAny;
205use crate::{
206 conversion::{AsPyPointer, FromPyPointer, ToPyObject},
207 type_object::get_tp_free,
208 PyTypeInfo,
209};
210use crate::{ffi, IntoPy, PyErr, PyNativeType, PyObject, PyResult, Python};
211use std::cell::UnsafeCell;
212use std::fmt;
213use std::mem::ManuallyDrop;
214use std::ops::{Deref, DerefMut};
215
216pub(crate) mod impl_;
217use impl_::{GetBorrowChecker, PyClassBorrowChecker, PyClassMutability};
218
219/// Base layout of PyCell.
220#[doc(hidden)]
221#[repr(C)]
222pub struct PyCellBase<T> {
223 ob_base: T,
224}
225
226unsafe impl<T, U> PyLayout<T> for PyCellBase<U> where U: PySizedLayout<T> {}
227
228/// A container type for (mutably) accessing [`PyClass`] values
229///
230/// `PyCell` autodereferences to [`PyAny`], so you can call `PyAny`'s methods on a `PyCell<T>`.
231///
232/// # Examples
233///
234/// This example demonstrates getting a mutable reference of the contained `PyClass`.
235/// ```rust
236/// use pyo3::prelude::*;
237///
238/// #[pyclass]
239/// struct Number {
240/// inner: u32,
241/// }
242///
243/// #[pymethods]
244/// impl Number {
245/// fn increment(&mut self) {
246/// self.inner += 1;
247/// }
248/// }
249///
250/// # fn main() -> PyResult<()> {
251/// Python::with_gil(|py| {
252/// let n = PyCell::new(py, Number { inner: 0 })?;
253///
254/// let n_mutable: &mut Number = &mut n.borrow_mut();
255/// n_mutable.increment();
256///
257/// Ok(())
258/// })
259/// # }
260/// ```
261/// For more information on how, when and why (not) to use `PyCell` please see the
262/// [module-level documentation](self).
263#[repr(C)]
264pub struct PyCell<T: PyClassImpl> {
265 ob_base: <T::BaseType as PyClassBaseType>::LayoutAsBase,
266 contents: PyCellContents<T>,
267}
268
269#[repr(C)]
270pub(crate) struct PyCellContents<T: PyClassImpl> {
271 pub(crate) value: ManuallyDrop<UnsafeCell<T>>,
272 pub(crate) borrow_checker: <T::PyClassMutability as PyClassMutability>::Storage,
273 pub(crate) thread_checker: T::ThreadChecker,
274 pub(crate) dict: T::Dict,
275 pub(crate) weakref: T::WeakRef,
276}
277
278unsafe impl<T: PyClass> PyNativeType for PyCell<T> {}
279
280impl<T: PyClass> PyCell<T> {
281 /// Makes a new `PyCell` on the Python heap and return the reference to it.
282 ///
283 /// In cases where the value in the cell does not need to be accessed immediately after
284 /// creation, consider [`Py::new`](crate::Py::new) as a more efficient alternative.
285 pub fn new(py: Python<'_>, value: impl Into<PyClassInitializer<T>>) -> PyResult<&Self> {
286 unsafe {
287 let initializer = value.into();
288 let self_ = initializer.create_cell(py)?;
289 FromPyPointer::from_owned_ptr_or_err(py, self_ as _)
290 }
291 }
292
293 /// Immutably borrows the value `T`. This borrow lasts as long as the returned `PyRef` exists.
294 ///
295 /// For frozen classes, the simpler [`get`][Self::get] is available.
296 ///
297 /// # Panics
298 ///
299 /// Panics if the value is currently mutably borrowed. For a non-panicking variant, use
300 /// [`try_borrow`](#method.try_borrow).
301 pub fn borrow(&self) -> PyRef<'_, T> {
302 self.try_borrow().expect("Already mutably borrowed")
303 }
304
305 /// Mutably borrows the value `T`. This borrow lasts as long as the returned `PyRefMut` exists.
306 ///
307 /// # Panics
308 ///
309 /// Panics if the value is currently borrowed. For a non-panicking variant, use
310 /// [`try_borrow_mut`](#method.try_borrow_mut).
311 pub fn borrow_mut(&self) -> PyRefMut<'_, T>
312 where
313 T: PyClass<Frozen = False>,
314 {
315 self.try_borrow_mut().expect("Already borrowed")
316 }
317
318 /// Immutably borrows the value `T`, returning an error if the value is currently
319 /// mutably borrowed. This borrow lasts as long as the returned `PyRef` exists.
320 ///
321 /// This is the non-panicking variant of [`borrow`](#method.borrow).
322 ///
323 /// For frozen classes, the simpler [`get`][Self::get] is available.
324 ///
325 /// # Examples
326 ///
327 /// ```
328 /// # use pyo3::prelude::*;
329 /// #[pyclass]
330 /// struct Class {}
331 ///
332 /// Python::with_gil(|py| {
333 /// let c = PyCell::new(py, Class {}).unwrap();
334 /// {
335 /// let m = c.borrow_mut();
336 /// assert!(c.try_borrow().is_err());
337 /// }
338 ///
339 /// {
340 /// let m = c.borrow();
341 /// assert!(c.try_borrow().is_ok());
342 /// }
343 /// });
344 /// ```
345 pub fn try_borrow(&self) -> Result<PyRef<'_, T>, PyBorrowError> {
346 self.ensure_threadsafe();
347 self.borrow_checker()
348 .try_borrow()
349 .map(|_| PyRef { inner: self })
350 }
351
352 /// Mutably borrows the value `T`, returning an error if the value is currently borrowed.
353 /// This borrow lasts as long as the returned `PyRefMut` exists.
354 ///
355 /// This is the non-panicking variant of [`borrow_mut`](#method.borrow_mut).
356 ///
357 /// # Examples
358 ///
359 /// ```
360 /// # use pyo3::prelude::*;
361 /// #[pyclass]
362 /// struct Class {}
363 /// Python::with_gil(|py| {
364 /// let c = PyCell::new(py, Class {}).unwrap();
365 /// {
366 /// let m = c.borrow();
367 /// assert!(c.try_borrow_mut().is_err());
368 /// }
369 ///
370 /// assert!(c.try_borrow_mut().is_ok());
371 /// });
372 /// ```
373 pub fn try_borrow_mut(&self) -> Result<PyRefMut<'_, T>, PyBorrowMutError>
374 where
375 T: PyClass<Frozen = False>,
376 {
377 self.ensure_threadsafe();
378 self.borrow_checker()
379 .try_borrow_mut()
380 .map(|_| PyRefMut { inner: self })
381 }
382
383 /// Immutably borrows the value `T`, returning an error if the value is
384 /// currently mutably borrowed.
385 ///
386 /// # Safety
387 ///
388 /// This method is unsafe because it does not return a `PyRef`,
389 /// thus leaving the borrow flag untouched. Mutably borrowing the `PyCell`
390 /// while the reference returned by this method is alive is undefined behaviour.
391 ///
392 /// # Examples
393 ///
394 /// ```
395 /// # use pyo3::prelude::*;
396 /// #[pyclass]
397 /// struct Class {}
398 /// Python::with_gil(|py| {
399 /// let c = PyCell::new(py, Class {}).unwrap();
400 ///
401 /// {
402 /// let m = c.borrow_mut();
403 /// assert!(unsafe { c.try_borrow_unguarded() }.is_err());
404 /// }
405 ///
406 /// {
407 /// let m = c.borrow();
408 /// assert!(unsafe { c.try_borrow_unguarded() }.is_ok());
409 /// }
410 /// });
411 /// ```
412 pub unsafe fn try_borrow_unguarded(&self) -> Result<&T, PyBorrowError> {
413 self.ensure_threadsafe();
414 self.borrow_checker()
415 .try_borrow_unguarded()
416 .map(|_: ()| &*self.contents.value.get())
417 }
418
419 /// Provide an immutable borrow of the value `T` without acquiring the GIL.
420 ///
421 /// This is available if the class is [`frozen`][macro@crate::pyclass] and [`Sync`].
422 ///
423 /// While the GIL is usually required to get access to `&PyCell<T>`,
424 /// compared to [`borrow`][Self::borrow] or [`try_borrow`][Self::try_borrow]
425 /// this avoids any thread or borrow checking overhead at runtime.
426 ///
427 /// # Examples
428 ///
429 /// ```
430 /// use std::sync::atomic::{AtomicUsize, Ordering};
431 /// # use pyo3::prelude::*;
432 ///
433 /// #[pyclass(frozen)]
434 /// struct FrozenCounter {
435 /// value: AtomicUsize,
436 /// }
437 ///
438 /// Python::with_gil(|py| {
439 /// let counter = FrozenCounter { value: AtomicUsize::new(0) };
440 ///
441 /// let cell = PyCell::new(py, counter).unwrap();
442 ///
443 /// cell.get().value.fetch_add(1, Ordering::Relaxed);
444 /// });
445 /// ```
446 pub fn get(&self) -> &T
447 where
448 T: PyClass<Frozen = True> + Sync,
449 {
450 // SAFETY: The class itself is frozen and `Sync` and we do not access anything but `self.contents.value`.
451 unsafe { &*self.get_ptr() }
452 }
453
454 /// Replaces the wrapped value with a new one, returning the old value.
455 ///
456 /// # Panics
457 ///
458 /// Panics if the value is currently borrowed.
459 #[inline]
460 pub fn replace(&self, t: T) -> T
461 where
462 T: PyClass<Frozen = False>,
463 {
464 std::mem::replace(&mut *self.borrow_mut(), t)
465 }
466
467 /// Replaces the wrapped value with a new one computed from `f`, returning the old value.
468 ///
469 /// # Panics
470 ///
471 /// Panics if the value is currently borrowed.
472 pub fn replace_with<F: FnOnce(&mut T) -> T>(&self, f: F) -> T
473 where
474 T: PyClass<Frozen = False>,
475 {
476 let mut_borrow = &mut *self.borrow_mut();
477 let replacement = f(mut_borrow);
478 std::mem::replace(mut_borrow, replacement)
479 }
480
481 /// Swaps the wrapped value of `self` with the wrapped value of `other`.
482 ///
483 /// # Panics
484 ///
485 /// Panics if the value in either `PyCell` is currently borrowed.
486 #[inline]
487 pub fn swap(&self, other: &Self)
488 where
489 T: PyClass<Frozen = False>,
490 {
491 std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
492 }
493
494 pub(crate) fn get_ptr(&self) -> *mut T {
495 self.contents.value.get()
496 }
497
498 /// Gets the offset of the dictionary from the start of the struct in bytes.
499 pub(crate) fn dict_offset() -> ffi::Py_ssize_t {
500 use memoffset::offset_of;
501
502 let offset = offset_of!(PyCell<T>, contents) + offset_of!(PyCellContents<T>, dict);
503
504 // Py_ssize_t may not be equal to isize on all platforms
505 #[allow(clippy::useless_conversion)]
506 offset.try_into().expect("offset should fit in Py_ssize_t")
507 }
508
509 /// Gets the offset of the weakref list from the start of the struct in bytes.
510 pub(crate) fn weaklist_offset() -> ffi::Py_ssize_t {
511 use memoffset::offset_of;
512
513 let offset = offset_of!(PyCell<T>, contents) + offset_of!(PyCellContents<T>, weakref);
514
515 // Py_ssize_t may not be equal to isize on all platforms
516 #[allow(clippy::useless_conversion)]
517 offset.try_into().expect("offset should fit in Py_ssize_t")
518 }
519}
520
521impl<T: PyClassImpl> PyCell<T> {
522 fn borrow_checker(&self) -> &<T::PyClassMutability as PyClassMutability>::Checker {
523 T::PyClassMutability::borrow_checker(self)
524 }
525}
526
527unsafe impl<T: PyClassImpl> PyLayout<T> for PyCell<T> {}
528impl<T: PyClass> PySizedLayout<T> for PyCell<T> {}
529
530unsafe impl<T: PyClass> AsPyPointer for PyCell<T> {
531 fn as_ptr(&self) -> *mut ffi::PyObject {
532 (self as *const _) as *mut _
533 }
534}
535
536impl<T: PyClass> ToPyObject for &PyCell<T> {
537 fn to_object(&self, py: Python<'_>) -> PyObject {
538 unsafe { PyObject::from_borrowed_ptr(py, self.as_ptr()) }
539 }
540}
541
542impl<T: PyClass> AsRef<PyAny> for PyCell<T> {
543 fn as_ref(&self) -> &PyAny {
544 unsafe { self.py().from_borrowed_ptr(self.as_ptr()) }
545 }
546}
547
548impl<T: PyClass> Deref for PyCell<T> {
549 type Target = PyAny;
550
551 fn deref(&self) -> &PyAny {
552 unsafe { self.py().from_borrowed_ptr(self.as_ptr()) }
553 }
554}
555
556impl<T: PyClass + fmt::Debug> fmt::Debug for PyCell<T> {
557 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
558 match self.try_borrow() {
559 Ok(borrow: PyRef<'_, T>) => f.debug_struct("RefCell").field(name:"value", &borrow).finish(),
560 Err(_) => {
561 struct BorrowedPlaceholder;
562 impl fmt::Debug for BorrowedPlaceholder {
563 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564 f.write_str(data:"<borrowed>")
565 }
566 }
567 f&mut DebugStruct<'_, '_>.debug_struct("RefCell")
568 .field(name:"value", &BorrowedPlaceholder)
569 .finish()
570 }
571 }
572 }
573}
574
575/// A wrapper type for an immutably borrowed value from a [`PyCell`]`<T>`.
576///
577/// See the [`PyCell`] documentation for more information.
578///
579/// # Examples
580///
581/// You can use `PyRef` as an alternative to a `&self` receiver when
582/// - you need to access the pointer of the `PyCell`, or
583/// - you want to get a super class.
584/// ```
585/// # use pyo3::prelude::*;
586/// #[pyclass(subclass)]
587/// struct Parent {
588/// basename: &'static str,
589/// }
590///
591/// #[pyclass(extends=Parent)]
592/// struct Child {
593/// name: &'static str,
594/// }
595///
596/// #[pymethods]
597/// impl Child {
598/// #[new]
599/// fn new() -> (Self, Parent) {
600/// (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" })
601/// }
602///
603/// fn format(slf: PyRef<'_, Self>) -> String {
604/// // We can get *mut ffi::PyObject from PyRef
605/// let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) };
606/// // We can get &Self::BaseType by as_ref
607/// let basename = slf.as_ref().basename;
608/// format!("{}(base: {}, cnt: {})", slf.name, basename, refcnt)
609/// }
610/// }
611/// # Python::with_gil(|py| {
612/// # let sub = PyCell::new(py, Child::new()).unwrap();
613/// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 3)'");
614/// # });
615/// ```
616///
617/// See the [module-level documentation](self) for more information.
618pub struct PyRef<'p, T: PyClass> {
619 inner: &'p PyCell<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 unsafe { &*self.inner.ob_base.get_ptr() }
636 }
637}
638
639impl<'p, T: PyClass> PyRef<'p, 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.into_ptr()
662 }
663}
664
665impl<'p, T, U> PyRef<'p, T>
666where
667 T: PyClass<BaseType = U>,
668 U: PyClass,
669{
670 /// Gets a `PyRef<T::BaseType>`.
671 ///
672 /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be
673 /// used to get the base of `T::BaseType`.
674 ///
675 /// But with the help of this method, you can get hold of instances of the
676 /// super-superclass when needed.
677 ///
678 /// # Examples
679 /// ```
680 /// # use pyo3::prelude::*;
681 /// #[pyclass(subclass)]
682 /// struct Base1 {
683 /// name1: &'static str,
684 /// }
685 ///
686 /// #[pyclass(extends=Base1, subclass)]
687 /// struct Base2 {
688 /// name2: &'static str,
689 /// }
690 ///
691 /// #[pyclass(extends=Base2)]
692 /// struct Sub {
693 /// name3: &'static str,
694 /// }
695 ///
696 /// #[pymethods]
697 /// impl Sub {
698 /// #[new]
699 /// fn new() -> PyClassInitializer<Self> {
700 /// PyClassInitializer::from(Base1 { name1: "base1" })
701 /// .add_subclass(Base2 { name2: "base2" })
702 /// .add_subclass(Self { name3: "sub" })
703 /// }
704 /// fn name(slf: PyRef<'_, Self>) -> String {
705 /// let subname = slf.name3;
706 /// let super_ = slf.into_super();
707 /// format!("{} {} {}", super_.as_ref().name1, super_.name2, subname)
708 /// }
709 /// }
710 /// # Python::with_gil(|py| {
711 /// # let sub = PyCell::new(py, Sub::new()).unwrap();
712 /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'")
713 /// # });
714 /// ```
715 pub fn into_super(self) -> PyRef<'p, U> {
716 let PyRef { inner } = self;
717 std::mem::forget(self);
718 PyRef {
719 inner: &inner.ob_base,
720 }
721 }
722}
723
724impl<'p, T: PyClass> Deref for PyRef<'p, T> {
725 type Target = T;
726
727 #[inline]
728 fn deref(&self) -> &T {
729 unsafe { &*self.inner.get_ptr() }
730 }
731}
732
733impl<'p, T: PyClass> Drop for PyRef<'p, T> {
734 fn drop(&mut self) {
735 self.inner.borrow_checker().release_borrow()
736 }
737}
738
739impl<T: PyClass> IntoPy<PyObject> for PyRef<'_, T> {
740 fn into_py(self, py: Python<'_>) -> PyObject {
741 unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
742 }
743}
744
745impl<T: PyClass> IntoPy<PyObject> for &'_ PyRef<'_, T> {
746 fn into_py(self, py: Python<'_>) -> PyObject {
747 self.inner.into_py(py)
748 }
749}
750
751impl<'a, T: PyClass> std::convert::TryFrom<&'a PyCell<T>> for crate::PyRef<'a, T> {
752 type Error = PyBorrowError;
753 fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
754 cell.try_borrow()
755 }
756}
757
758unsafe impl<'a, T: PyClass> AsPyPointer for PyRef<'a, T> {
759 fn as_ptr(&self) -> *mut ffi::PyObject {
760 self.inner.as_ptr()
761 }
762}
763
764impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> {
765 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
766 fmt::Debug::fmt(&**self, f)
767 }
768}
769
770/// A wrapper type for a mutably borrowed value from a[`PyCell`]`<T>`.
771///
772/// See the [module-level documentation](self) for more information.
773pub struct PyRefMut<'p, T: PyClass<Frozen = False>> {
774 inner: &'p PyCell<T>,
775}
776
777impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
778 /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`.
779 pub fn py(&self) -> Python<'p> {
780 self.inner.py()
781 }
782}
783
784impl<'p, T, U> AsRef<U> for PyRefMut<'p, T>
785where
786 T: PyClass<BaseType = U, Frozen = False>,
787 U: PyClass<Frozen = False>,
788{
789 fn as_ref(&self) -> &T::BaseType {
790 unsafe { &*self.inner.ob_base.get_ptr() }
791 }
792}
793
794impl<'p, T, U> AsMut<U> for PyRefMut<'p, T>
795where
796 T: PyClass<BaseType = U, Frozen = False>,
797 U: PyClass<Frozen = False>,
798{
799 fn as_mut(&mut self) -> &mut T::BaseType {
800 unsafe { &mut *self.inner.ob_base.get_ptr() }
801 }
802}
803
804impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> {
805 /// Returns the raw FFI pointer represented by self.
806 ///
807 /// # Safety
808 ///
809 /// Callers are responsible for ensuring that the pointer does not outlive self.
810 ///
811 /// The reference is borrowed; callers should not decrease the reference count
812 /// when they are finished with the pointer.
813 #[inline]
814 pub fn as_ptr(&self) -> *mut ffi::PyObject {
815 self.inner.as_ptr()
816 }
817
818 /// Returns an owned raw FFI pointer represented by self.
819 ///
820 /// # Safety
821 ///
822 /// The reference is owned; when finished the caller should either transfer ownership
823 /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)).
824 #[inline]
825 pub fn into_ptr(self) -> *mut ffi::PyObject {
826 self.inner.into_ptr()
827 }
828}
829
830impl<'p, T, U> PyRefMut<'p, T>
831where
832 T: PyClass<BaseType = U, Frozen = False>,
833 U: PyClass<Frozen = False>,
834{
835 /// Gets a `PyRef<T::BaseType>`.
836 ///
837 /// See [`PyRef::into_super`] for more.
838 pub fn into_super(self) -> PyRefMut<'p, U> {
839 let PyRefMut { inner: &PyCell } = self;
840 std::mem::forget(self);
841 PyRefMut {
842 inner: &inner.ob_base,
843 }
844 }
845}
846
847impl<'p, T: PyClass<Frozen = False>> Deref for PyRefMut<'p, T> {
848 type Target = T;
849
850 #[inline]
851 fn deref(&self) -> &T {
852 unsafe { &*self.inner.get_ptr() }
853 }
854}
855
856impl<'p, T: PyClass<Frozen = False>> DerefMut for PyRefMut<'p, T> {
857 #[inline]
858 fn deref_mut(&mut self) -> &mut T {
859 unsafe { &mut *self.inner.get_ptr() }
860 }
861}
862
863impl<'p, T: PyClass<Frozen = False>> Drop for PyRefMut<'p, T> {
864 fn drop(&mut self) {
865 self.inner.borrow_checker().release_borrow_mut()
866 }
867}
868
869impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for PyRefMut<'_, T> {
870 fn into_py(self, py: Python<'_>) -> PyObject {
871 unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) }
872 }
873}
874
875impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for &'_ PyRefMut<'_, T> {
876 fn into_py(self, py: Python<'_>) -> PyObject {
877 self.inner.into_py(py)
878 }
879}
880
881unsafe impl<'a, T: PyClass<Frozen = False>> AsPyPointer for PyRefMut<'a, T> {
882 fn as_ptr(&self) -> *mut ffi::PyObject {
883 self.inner.as_ptr()
884 }
885}
886
887impl<'a, T: PyClass<Frozen = False>> std::convert::TryFrom<&'a PyCell<T>>
888 for crate::PyRefMut<'a, T>
889{
890 type Error = PyBorrowMutError;
891 fn try_from(cell: &'a crate::PyCell<T>) -> Result<Self, Self::Error> {
892 cell.try_borrow_mut()
893 }
894}
895
896impl<T: PyClass<Frozen = False> + fmt::Debug> fmt::Debug for PyRefMut<'_, T> {
897 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
898 fmt::Debug::fmt(self.deref(), f)
899 }
900}
901
902/// An error type returned by [`PyCell::try_borrow`].
903///
904/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
905pub struct PyBorrowError {
906 _private: (),
907}
908
909impl fmt::Debug for PyBorrowError {
910 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911 f.debug_struct(name:"PyBorrowError").finish()
912 }
913}
914
915impl fmt::Display for PyBorrowError {
916 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
917 fmt::Display::fmt(self:"Already mutably borrowed", f)
918 }
919}
920
921impl From<PyBorrowError> for PyErr {
922 fn from(other: PyBorrowError) -> Self {
923 PyRuntimeError::new_err(args:other.to_string())
924 }
925}
926
927/// An error type returned by [`PyCell::try_borrow_mut`].
928///
929/// If this error is allowed to bubble up into Python code it will raise a `RuntimeError`.
930pub struct PyBorrowMutError {
931 _private: (),
932}
933
934impl fmt::Debug for PyBorrowMutError {
935 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
936 f.debug_struct(name:"PyBorrowMutError").finish()
937 }
938}
939
940impl fmt::Display for PyBorrowMutError {
941 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
942 fmt::Display::fmt(self:"Already borrowed", f)
943 }
944}
945
946impl From<PyBorrowMutError> for PyErr {
947 fn from(other: PyBorrowMutError) -> Self {
948 PyRuntimeError::new_err(args:other.to_string())
949 }
950}
951
952#[doc(hidden)]
953pub trait PyCellLayout<T>: PyLayout<T> {
954 fn ensure_threadsafe(&self);
955 /// Implementation of tp_dealloc.
956 /// # Safety
957 /// - slf must be a valid pointer to an instance of a T or a subclass.
958 /// - slf must not be used after this call (as it will be freed).
959 unsafe fn tp_dealloc(py: Python<'_>, slf: *mut ffi::PyObject);
960}
961
962impl<T, U> PyCellLayout<T> for PyCellBase<U>
963where
964 U: PySizedLayout<T>,
965 T: PyTypeInfo,
966{
967 fn ensure_threadsafe(&self) {}
968 unsafe fn tp_dealloc(py: Python<'_>, slf: *mut ffi::PyObject) {
969 let type_obj = T::type_object_raw(py);
970 // For `#[pyclass]` types which inherit from PyAny, we can just call tp_free
971 if type_obj == std::ptr::addr_of_mut!(ffi::PyBaseObject_Type) {
972 return get_tp_free(ffi::Py_TYPE(slf))(slf as _);
973 }
974
975 // More complex native types (e.g. `extends=PyDict`) require calling the base's dealloc.
976 #[cfg(not(Py_LIMITED_API))]
977 {
978 if let Some(dealloc) = (*type_obj).tp_dealloc {
979 // Before CPython 3.11 BaseException_dealloc would use Py_GC_UNTRACK which
980 // assumes the exception is currently GC tracked, so we have to re-track
981 // before calling the dealloc so that it can safely call Py_GC_UNTRACK.
982 #[cfg(not(any(Py_3_11, PyPy)))]
983 if ffi::PyType_FastSubclass(type_obj, ffi::Py_TPFLAGS_BASE_EXC_SUBCLASS) == 1 {
984 ffi::PyObject_GC_Track(slf.cast());
985 }
986 dealloc(slf as _);
987 } else {
988 get_tp_free(ffi::Py_TYPE(slf))(slf as _);
989 }
990 }
991
992 #[cfg(Py_LIMITED_API)]
993 unreachable!("subclassing native types is not possible with the `abi3` feature");
994 }
995}
996
997impl<T: PyClassImpl> PyCellLayout<T> for PyCell<T>
998where
999 <T::BaseType as PyClassBaseType>::LayoutAsBase: PyCellLayout<T::BaseType>,
1000{
1001 fn ensure_threadsafe(&self) {
1002 self.contents.thread_checker.ensure();
1003 self.ob_base.ensure_threadsafe();
1004 }
1005 unsafe fn tp_dealloc(py: Python<'_>, slf: *mut ffi::PyObject) {
1006 // Safety: Python only calls tp_dealloc when no references to the object remain.
1007 let cell: &mut PyCell = &mut *(slf as *mut PyCell<T>);
1008 if cell.contents.thread_checker.can_drop(py) {
1009 ManuallyDrop::drop(&mut cell.contents.value);
1010 }
1011 cell.contents.dict.clear_dict(py);
1012 cell.contents.weakref.clear_weakrefs(_obj:slf, py);
1013 <T::BaseType as PyClassBaseType>::LayoutAsBase::tp_dealloc(py, slf)
1014 }
1015}
1016
1017#[cfg(test)]
1018#[cfg(feature = "macros")]
1019mod tests {
1020
1021 use super::*;
1022
1023 #[crate::pyclass]
1024 #[pyo3(crate = "crate")]
1025 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
1026 struct SomeClass(i32);
1027
1028 #[test]
1029 fn pycell_replace() {
1030 Python::with_gil(|py| {
1031 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1032 assert_eq!(*cell.borrow(), SomeClass(0));
1033
1034 let previous = cell.replace(SomeClass(123));
1035 assert_eq!(previous, SomeClass(0));
1036 assert_eq!(*cell.borrow(), SomeClass(123));
1037 })
1038 }
1039
1040 #[test]
1041 #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1042 fn pycell_replace_panic() {
1043 Python::with_gil(|py| {
1044 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1045 let _guard = cell.borrow();
1046
1047 cell.replace(SomeClass(123));
1048 })
1049 }
1050
1051 #[test]
1052 fn pycell_replace_with() {
1053 Python::with_gil(|py| {
1054 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1055 assert_eq!(*cell.borrow(), SomeClass(0));
1056
1057 let previous = cell.replace_with(|value| {
1058 *value = SomeClass(2);
1059 SomeClass(123)
1060 });
1061 assert_eq!(previous, SomeClass(2));
1062 assert_eq!(*cell.borrow(), SomeClass(123));
1063 })
1064 }
1065
1066 #[test]
1067 #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1068 fn pycell_replace_with_panic() {
1069 Python::with_gil(|py| {
1070 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1071 let _guard = cell.borrow();
1072
1073 cell.replace_with(|_| SomeClass(123));
1074 })
1075 }
1076
1077 #[test]
1078 fn pycell_swap() {
1079 Python::with_gil(|py| {
1080 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1081 let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1082 assert_eq!(*cell.borrow(), SomeClass(0));
1083 assert_eq!(*cell2.borrow(), SomeClass(123));
1084
1085 cell.swap(cell2);
1086 assert_eq!(*cell.borrow(), SomeClass(123));
1087 assert_eq!(*cell2.borrow(), SomeClass(0));
1088 })
1089 }
1090
1091 #[test]
1092 #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1093 fn pycell_swap_panic() {
1094 Python::with_gil(|py| {
1095 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1096 let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1097
1098 let _guard = cell.borrow();
1099 cell.swap(cell2);
1100 })
1101 }
1102
1103 #[test]
1104 #[should_panic(expected = "Already borrowed: PyBorrowMutError")]
1105 fn pycell_swap_panic_other_borrowed() {
1106 Python::with_gil(|py| {
1107 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1108 let cell2 = PyCell::new(py, SomeClass(123)).unwrap();
1109
1110 let _guard = cell2.borrow();
1111 cell.swap(cell2);
1112 })
1113 }
1114
1115 #[test]
1116 fn test_as_ptr() {
1117 Python::with_gil(|py| {
1118 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1119 let ptr = cell.as_ptr();
1120
1121 assert_eq!(cell.borrow().as_ptr(), ptr);
1122 assert_eq!(cell.borrow_mut().as_ptr(), ptr);
1123 })
1124 }
1125
1126 #[test]
1127 fn test_into_ptr() {
1128 Python::with_gil(|py| {
1129 let cell = PyCell::new(py, SomeClass(0)).unwrap();
1130 let ptr = cell.as_ptr();
1131
1132 assert_eq!(cell.borrow().into_ptr(), ptr);
1133 unsafe { ffi::Py_DECREF(ptr) };
1134
1135 assert_eq!(cell.borrow_mut().into_ptr(), ptr);
1136 unsafe { ffi::Py_DECREF(ptr) };
1137 })
1138 }
1139}
1140