| 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 |
| 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::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::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!(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!(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!(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 | |
| 196 | use crate::conversion::{AsPyPointer, IntoPyObject}; |
| 197 | use crate::exceptions::PyRuntimeError; |
| 198 | use crate::ffi_ptr_ext::FfiPtrExt; |
| 199 | use crate::internal_tricks::{ptr_from_mut, ptr_from_ref}; |
| 200 | use crate::pyclass::{boolean_struct::False, PyClass}; |
| 201 | use crate::types::any::PyAnyMethods; |
| 202 | #[allow (deprecated)] |
| 203 | use crate::IntoPy; |
| 204 | use crate::{ffi, Borrowed, Bound, PyErr, PyObject, Python}; |
| 205 | use std::convert::Infallible; |
| 206 | use std::fmt; |
| 207 | use std::mem::ManuallyDrop; |
| 208 | use std::ops::{Deref, DerefMut}; |
| 209 | |
| 210 | pub(crate) mod impl_; |
| 211 | use impl_::{PyClassBorrowChecker, PyClassObjectLayout}; |
| 212 | |
| 213 | /// A wrapper type for an immutably borrowed value from a [`Bound<'py, T>`]. |
| 214 | /// |
| 215 | /// See the [`Bound`] documentation for more information. |
| 216 | /// |
| 217 | /// # Examples |
| 218 | /// |
| 219 | /// You can use [`PyRef`] as an alternative to a `&self` receiver when |
| 220 | /// - you need to access the pointer of the [`Bound`], or |
| 221 | /// - you want to get a super class. |
| 222 | /// ``` |
| 223 | /// # use pyo3::prelude::*; |
| 224 | /// #[pyclass(subclass)] |
| 225 | /// struct Parent { |
| 226 | /// basename: &'static str, |
| 227 | /// } |
| 228 | /// |
| 229 | /// #[pyclass(extends=Parent)] |
| 230 | /// struct Child { |
| 231 | /// name: &'static str, |
| 232 | /// } |
| 233 | /// |
| 234 | /// #[pymethods] |
| 235 | /// impl Child { |
| 236 | /// #[new] |
| 237 | /// fn new() -> (Self, Parent) { |
| 238 | /// (Child { name: "Caterpillar" }, Parent { basename: "Butterfly" }) |
| 239 | /// } |
| 240 | /// |
| 241 | /// fn format(slf: PyRef<'_, Self>) -> String { |
| 242 | /// // We can get *mut ffi::PyObject from PyRef |
| 243 | /// let refcnt = unsafe { pyo3::ffi::Py_REFCNT(slf.as_ptr()) }; |
| 244 | /// // We can get &Self::BaseType by as_ref |
| 245 | /// let basename = slf.as_ref().basename; |
| 246 | /// format!("{}(base: {}, cnt: {})" , slf.name, basename, refcnt) |
| 247 | /// } |
| 248 | /// } |
| 249 | /// # Python::with_gil(|py| { |
| 250 | /// # let sub = Py::new(py, Child::new()).unwrap(); |
| 251 | /// # pyo3::py_run!(py, sub, "assert sub.format() == 'Caterpillar(base: Butterfly, cnt: 4)', sub.format()" ); |
| 252 | /// # }); |
| 253 | /// ``` |
| 254 | /// |
| 255 | /// See the [module-level documentation](self) for more information. |
| 256 | #[repr (transparent)] |
| 257 | pub struct PyRef<'p, T: PyClass> { |
| 258 | // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to |
| 259 | // store `Borrowed` here instead, avoiding reference counting overhead. |
| 260 | inner: Bound<'p, T>, |
| 261 | } |
| 262 | |
| 263 | impl<'p, T: PyClass> PyRef<'p, T> { |
| 264 | /// Returns a `Python` token that is bound to the lifetime of the `PyRef`. |
| 265 | pub fn py(&self) -> Python<'p> { |
| 266 | self.inner.py() |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | impl<T, U> AsRef<U> for PyRef<'_, T> |
| 271 | where |
| 272 | T: PyClass<BaseType = U>, |
| 273 | U: PyClass, |
| 274 | { |
| 275 | fn as_ref(&self) -> &T::BaseType { |
| 276 | self.as_super() |
| 277 | } |
| 278 | } |
| 279 | |
| 280 | impl<'py, T: PyClass> PyRef<'py, T> { |
| 281 | /// Returns the raw FFI pointer represented by self. |
| 282 | /// |
| 283 | /// # Safety |
| 284 | /// |
| 285 | /// Callers are responsible for ensuring that the pointer does not outlive self. |
| 286 | /// |
| 287 | /// The reference is borrowed; callers should not decrease the reference count |
| 288 | /// when they are finished with the pointer. |
| 289 | #[inline ] |
| 290 | pub fn as_ptr(&self) -> *mut ffi::PyObject { |
| 291 | self.inner.as_ptr() |
| 292 | } |
| 293 | |
| 294 | /// Returns an owned raw FFI pointer represented by self. |
| 295 | /// |
| 296 | /// # Safety |
| 297 | /// |
| 298 | /// The reference is owned; when finished the caller should either transfer ownership |
| 299 | /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)). |
| 300 | #[inline ] |
| 301 | pub fn into_ptr(self) -> *mut ffi::PyObject { |
| 302 | self.inner.clone().into_ptr() |
| 303 | } |
| 304 | |
| 305 | #[track_caller ] |
| 306 | pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self { |
| 307 | Self::try_borrow(obj).expect("Already mutably borrowed" ) |
| 308 | } |
| 309 | |
| 310 | pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowError> { |
| 311 | let cell = obj.get_class_object(); |
| 312 | cell.ensure_threadsafe(); |
| 313 | cell.borrow_checker() |
| 314 | .try_borrow() |
| 315 | .map(|_| Self { inner: obj.clone() }) |
| 316 | } |
| 317 | } |
| 318 | |
| 319 | impl<'p, T, U> PyRef<'p, T> |
| 320 | where |
| 321 | T: PyClass<BaseType = U>, |
| 322 | U: PyClass, |
| 323 | { |
| 324 | /// Gets a `PyRef<T::BaseType>`. |
| 325 | /// |
| 326 | /// While `as_ref()` returns a reference of type `&T::BaseType`, this cannot be |
| 327 | /// used to get the base of `T::BaseType`. |
| 328 | /// |
| 329 | /// But with the help of this method, you can get hold of instances of the |
| 330 | /// super-superclass when needed. |
| 331 | /// |
| 332 | /// # Examples |
| 333 | /// ``` |
| 334 | /// # use pyo3::prelude::*; |
| 335 | /// #[pyclass(subclass)] |
| 336 | /// struct Base1 { |
| 337 | /// name1: &'static str, |
| 338 | /// } |
| 339 | /// |
| 340 | /// #[pyclass(extends=Base1, subclass)] |
| 341 | /// struct Base2 { |
| 342 | /// name2: &'static str, |
| 343 | /// } |
| 344 | /// |
| 345 | /// #[pyclass(extends=Base2)] |
| 346 | /// struct Sub { |
| 347 | /// name3: &'static str, |
| 348 | /// } |
| 349 | /// |
| 350 | /// #[pymethods] |
| 351 | /// impl Sub { |
| 352 | /// #[new] |
| 353 | /// fn new() -> PyClassInitializer<Self> { |
| 354 | /// PyClassInitializer::from(Base1 { name1: "base1" }) |
| 355 | /// .add_subclass(Base2 { name2: "base2" }) |
| 356 | /// .add_subclass(Self { name3: "sub" }) |
| 357 | /// } |
| 358 | /// fn name(slf: PyRef<'_, Self>) -> String { |
| 359 | /// let subname = slf.name3; |
| 360 | /// let super_ = slf.into_super(); |
| 361 | /// format!("{} {} {}" , super_.as_ref().name1, super_.name2, subname) |
| 362 | /// } |
| 363 | /// } |
| 364 | /// # Python::with_gil(|py| { |
| 365 | /// # let sub = Py::new(py, Sub::new()).unwrap(); |
| 366 | /// # pyo3::py_run!(py, sub, "assert sub.name() == 'base1 base2 sub'" ) |
| 367 | /// # }); |
| 368 | /// ``` |
| 369 | pub fn into_super(self) -> PyRef<'p, U> { |
| 370 | let py = self.py(); |
| 371 | PyRef { |
| 372 | inner: unsafe { |
| 373 | ManuallyDrop::new(self) |
| 374 | .as_ptr() |
| 375 | .assume_owned_unchecked(py) |
| 376 | .downcast_into_unchecked() |
| 377 | }, |
| 378 | } |
| 379 | } |
| 380 | |
| 381 | /// Borrows a shared reference to `PyRef<T::BaseType>`. |
| 382 | /// |
| 383 | /// With the help of this method, you can access attributes and call methods |
| 384 | /// on the superclass without consuming the `PyRef<T>`. This method can also |
| 385 | /// be chained to access the super-superclass (and so on). |
| 386 | /// |
| 387 | /// # Examples |
| 388 | /// ``` |
| 389 | /// # use pyo3::prelude::*; |
| 390 | /// #[pyclass(subclass)] |
| 391 | /// struct Base { |
| 392 | /// base_name: &'static str, |
| 393 | /// } |
| 394 | /// #[pymethods] |
| 395 | /// impl Base { |
| 396 | /// fn base_name_len(&self) -> usize { |
| 397 | /// self.base_name.len() |
| 398 | /// } |
| 399 | /// } |
| 400 | /// |
| 401 | /// #[pyclass(extends=Base)] |
| 402 | /// struct Sub { |
| 403 | /// sub_name: &'static str, |
| 404 | /// } |
| 405 | /// |
| 406 | /// #[pymethods] |
| 407 | /// impl Sub { |
| 408 | /// #[new] |
| 409 | /// fn new() -> (Self, Base) { |
| 410 | /// (Self { sub_name: "sub_name" }, Base { base_name: "base_name" }) |
| 411 | /// } |
| 412 | /// fn sub_name_len(&self) -> usize { |
| 413 | /// self.sub_name.len() |
| 414 | /// } |
| 415 | /// fn format_name_lengths(slf: PyRef<'_, Self>) -> String { |
| 416 | /// format!("{} {}" , slf.as_super().base_name_len(), slf.sub_name_len()) |
| 417 | /// } |
| 418 | /// } |
| 419 | /// # Python::with_gil(|py| { |
| 420 | /// # let sub = Py::new(py, Sub::new()).unwrap(); |
| 421 | /// # pyo3::py_run!(py, sub, "assert sub.format_name_lengths() == '9 8'" ) |
| 422 | /// # }); |
| 423 | /// ``` |
| 424 | pub fn as_super(&self) -> &PyRef<'p, U> { |
| 425 | let ptr = ptr_from_ref::<Bound<'p, T>>(&self.inner) |
| 426 | // `Bound<T>` has the same layout as `Bound<T::BaseType>` |
| 427 | .cast::<Bound<'p, T::BaseType>>() |
| 428 | // `Bound<T::BaseType>` has the same layout as `PyRef<T::BaseType>` |
| 429 | .cast::<PyRef<'p, T::BaseType>>(); |
| 430 | unsafe { &*ptr } |
| 431 | } |
| 432 | } |
| 433 | |
| 434 | impl<T: PyClass> Deref for PyRef<'_, T> { |
| 435 | type Target = T; |
| 436 | |
| 437 | #[inline ] |
| 438 | fn deref(&self) -> &T { |
| 439 | unsafe { &*self.inner.get_class_object().get_ptr() } |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | impl<T: PyClass> Drop for PyRef<'_, T> { |
| 444 | fn drop(&mut self) { |
| 445 | self.inner |
| 446 | .get_class_object() |
| 447 | .borrow_checker() |
| 448 | .release_borrow() |
| 449 | } |
| 450 | } |
| 451 | |
| 452 | #[allow (deprecated)] |
| 453 | impl<T: PyClass> IntoPy<PyObject> for PyRef<'_, T> { |
| 454 | fn into_py(self, py: Python<'_>) -> PyObject { |
| 455 | unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) } |
| 456 | } |
| 457 | } |
| 458 | |
| 459 | #[allow (deprecated)] |
| 460 | impl<T: PyClass> IntoPy<PyObject> for &'_ PyRef<'_, T> { |
| 461 | fn into_py(self, py: Python<'_>) -> PyObject { |
| 462 | unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) } |
| 463 | } |
| 464 | } |
| 465 | |
| 466 | impl<'py, T: PyClass> IntoPyObject<'py> for PyRef<'py, T> { |
| 467 | type Target = T; |
| 468 | type Output = Bound<'py, T>; |
| 469 | type Error = Infallible; |
| 470 | |
| 471 | fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> { |
| 472 | Ok(self.inner.clone()) |
| 473 | } |
| 474 | } |
| 475 | |
| 476 | impl<'a, 'py, T: PyClass> IntoPyObject<'py> for &'a PyRef<'py, T> { |
| 477 | type Target = T; |
| 478 | type Output = Borrowed<'a, 'py, T>; |
| 479 | type Error = Infallible; |
| 480 | |
| 481 | fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> { |
| 482 | Ok(self.inner.as_borrowed()) |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | unsafe impl<T: PyClass> AsPyPointer for PyRef<'_, T> { |
| 487 | fn as_ptr(&self) -> *mut ffi::PyObject { |
| 488 | self.inner.as_ptr() |
| 489 | } |
| 490 | } |
| 491 | |
| 492 | impl<T: PyClass + fmt::Debug> fmt::Debug for PyRef<'_, T> { |
| 493 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 494 | fmt::Debug::fmt(&**self, f) |
| 495 | } |
| 496 | } |
| 497 | |
| 498 | /// A wrapper type for a mutably borrowed value from a [`Bound<'py, T>`]. |
| 499 | /// |
| 500 | /// See the [module-level documentation](self) for more information. |
| 501 | #[repr (transparent)] |
| 502 | pub struct PyRefMut<'p, T: PyClass<Frozen = False>> { |
| 503 | // TODO: once the GIL Ref API is removed, consider adding a lifetime parameter to `PyRef` to |
| 504 | // store `Borrowed` here instead, avoiding reference counting overhead. |
| 505 | inner: Bound<'p, T>, |
| 506 | } |
| 507 | |
| 508 | impl<'p, T: PyClass<Frozen = False>> PyRefMut<'p, T> { |
| 509 | /// Returns a `Python` token that is bound to the lifetime of the `PyRefMut`. |
| 510 | pub fn py(&self) -> Python<'p> { |
| 511 | self.inner.py() |
| 512 | } |
| 513 | } |
| 514 | |
| 515 | impl<T, U> AsRef<U> for PyRefMut<'_, T> |
| 516 | where |
| 517 | T: PyClass<BaseType = U, Frozen = False>, |
| 518 | U: PyClass<Frozen = False>, |
| 519 | { |
| 520 | fn as_ref(&self) -> &T::BaseType { |
| 521 | PyRefMut::downgrade(self).as_super() |
| 522 | } |
| 523 | } |
| 524 | |
| 525 | impl<T, U> AsMut<U> for PyRefMut<'_, T> |
| 526 | where |
| 527 | T: PyClass<BaseType = U, Frozen = False>, |
| 528 | U: PyClass<Frozen = False>, |
| 529 | { |
| 530 | fn as_mut(&mut self) -> &mut T::BaseType { |
| 531 | self.as_super() |
| 532 | } |
| 533 | } |
| 534 | |
| 535 | impl<'py, T: PyClass<Frozen = False>> PyRefMut<'py, T> { |
| 536 | /// Returns the raw FFI pointer represented by self. |
| 537 | /// |
| 538 | /// # Safety |
| 539 | /// |
| 540 | /// Callers are responsible for ensuring that the pointer does not outlive self. |
| 541 | /// |
| 542 | /// The reference is borrowed; callers should not decrease the reference count |
| 543 | /// when they are finished with the pointer. |
| 544 | #[inline ] |
| 545 | pub fn as_ptr(&self) -> *mut ffi::PyObject { |
| 546 | self.inner.as_ptr() |
| 547 | } |
| 548 | |
| 549 | /// Returns an owned raw FFI pointer represented by self. |
| 550 | /// |
| 551 | /// # Safety |
| 552 | /// |
| 553 | /// The reference is owned; when finished the caller should either transfer ownership |
| 554 | /// of the pointer or decrease the reference count (e.g. with [`pyo3::ffi::Py_DecRef`](crate::ffi::Py_DecRef)). |
| 555 | #[inline ] |
| 556 | pub fn into_ptr(self) -> *mut ffi::PyObject { |
| 557 | self.inner.clone().into_ptr() |
| 558 | } |
| 559 | |
| 560 | #[inline ] |
| 561 | #[track_caller ] |
| 562 | pub(crate) fn borrow(obj: &Bound<'py, T>) -> Self { |
| 563 | Self::try_borrow(obj).expect("Already borrowed" ) |
| 564 | } |
| 565 | |
| 566 | pub(crate) fn try_borrow(obj: &Bound<'py, T>) -> Result<Self, PyBorrowMutError> { |
| 567 | let cell = obj.get_class_object(); |
| 568 | cell.ensure_threadsafe(); |
| 569 | cell.borrow_checker() |
| 570 | .try_borrow_mut() |
| 571 | .map(|_| Self { inner: obj.clone() }) |
| 572 | } |
| 573 | |
| 574 | pub(crate) fn downgrade(slf: &Self) -> &PyRef<'py, T> { |
| 575 | // `PyRefMut<T>` and `PyRef<T>` have the same layout |
| 576 | unsafe { &*ptr_from_ref(slf).cast() } |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | impl<'p, T, U> PyRefMut<'p, T> |
| 581 | where |
| 582 | T: PyClass<BaseType = U, Frozen = False>, |
| 583 | U: PyClass<Frozen = False>, |
| 584 | { |
| 585 | /// Gets a `PyRef<T::BaseType>`. |
| 586 | /// |
| 587 | /// See [`PyRef::into_super`] for more. |
| 588 | pub fn into_super(self) -> PyRefMut<'p, U> { |
| 589 | let py = self.py(); |
| 590 | PyRefMut { |
| 591 | inner: unsafe { |
| 592 | ManuallyDrop::new(self) |
| 593 | .as_ptr() |
| 594 | .assume_owned_unchecked(py) |
| 595 | .downcast_into_unchecked() |
| 596 | }, |
| 597 | } |
| 598 | } |
| 599 | |
| 600 | /// Borrows a mutable reference to `PyRefMut<T::BaseType>`. |
| 601 | /// |
| 602 | /// With the help of this method, you can mutate attributes and call mutating |
| 603 | /// methods on the superclass without consuming the `PyRefMut<T>`. This method |
| 604 | /// can also be chained to access the super-superclass (and so on). |
| 605 | /// |
| 606 | /// See [`PyRef::as_super`] for more. |
| 607 | pub fn as_super(&mut self) -> &mut PyRefMut<'p, U> { |
| 608 | let ptr = ptr_from_mut::<Bound<'p, T>>(&mut self.inner) |
| 609 | // `Bound<T>` has the same layout as `Bound<T::BaseType>` |
| 610 | .cast::<Bound<'p, T::BaseType>>() |
| 611 | // `Bound<T::BaseType>` has the same layout as `PyRefMut<T::BaseType>`, |
| 612 | // and the mutable borrow on `self` prevents aliasing |
| 613 | .cast::<PyRefMut<'p, T::BaseType>>(); |
| 614 | unsafe { &mut *ptr } |
| 615 | } |
| 616 | } |
| 617 | |
| 618 | impl<T: PyClass<Frozen = False>> Deref for PyRefMut<'_, T> { |
| 619 | type Target = T; |
| 620 | |
| 621 | #[inline ] |
| 622 | fn deref(&self) -> &T { |
| 623 | unsafe { &*self.inner.get_class_object().get_ptr() } |
| 624 | } |
| 625 | } |
| 626 | |
| 627 | impl<T: PyClass<Frozen = False>> DerefMut for PyRefMut<'_, T> { |
| 628 | #[inline ] |
| 629 | fn deref_mut(&mut self) -> &mut T { |
| 630 | unsafe { &mut *self.inner.get_class_object().get_ptr() } |
| 631 | } |
| 632 | } |
| 633 | |
| 634 | impl<T: PyClass<Frozen = False>> Drop for PyRefMut<'_, T> { |
| 635 | fn drop(&mut self) { |
| 636 | self.inner |
| 637 | .get_class_object() |
| 638 | .borrow_checker() |
| 639 | .release_borrow_mut() |
| 640 | } |
| 641 | } |
| 642 | |
| 643 | #[allow (deprecated)] |
| 644 | impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for PyRefMut<'_, T> { |
| 645 | fn into_py(self, py: Python<'_>) -> PyObject { |
| 646 | unsafe { PyObject::from_borrowed_ptr(py, self.inner.as_ptr()) } |
| 647 | } |
| 648 | } |
| 649 | |
| 650 | #[allow (deprecated)] |
| 651 | impl<T: PyClass<Frozen = False>> IntoPy<PyObject> for &'_ PyRefMut<'_, T> { |
| 652 | fn into_py(self, py: Python<'_>) -> PyObject { |
| 653 | self.inner.clone().into_py(py) |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | impl<'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for PyRefMut<'py, T> { |
| 658 | type Target = T; |
| 659 | type Output = Bound<'py, T>; |
| 660 | type Error = Infallible; |
| 661 | |
| 662 | fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> { |
| 663 | Ok(self.inner.clone()) |
| 664 | } |
| 665 | } |
| 666 | |
| 667 | impl<'a, 'py, T: PyClass<Frozen = False>> IntoPyObject<'py> for &'a PyRefMut<'py, T> { |
| 668 | type Target = T; |
| 669 | type Output = Borrowed<'a, 'py, T>; |
| 670 | type Error = Infallible; |
| 671 | |
| 672 | fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> { |
| 673 | Ok(self.inner.as_borrowed()) |
| 674 | } |
| 675 | } |
| 676 | |
| 677 | impl<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`. |
| 686 | pub struct PyBorrowError { |
| 687 | _private: (), |
| 688 | } |
| 689 | |
| 690 | impl fmt::Debug for PyBorrowError { |
| 691 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 692 | f.debug_struct(name:"PyBorrowError" ).finish() |
| 693 | } |
| 694 | } |
| 695 | |
| 696 | impl fmt::Display for PyBorrowError { |
| 697 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 698 | fmt::Display::fmt(self:"Already mutably borrowed" , f) |
| 699 | } |
| 700 | } |
| 701 | |
| 702 | impl From<PyBorrowError> for PyErr { |
| 703 | fn from(other: PyBorrowError) -> Self { |
| 704 | PyRuntimeError::new_err(args: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`. |
| 711 | pub struct PyBorrowMutError { |
| 712 | _private: (), |
| 713 | } |
| 714 | |
| 715 | impl fmt::Debug for PyBorrowMutError { |
| 716 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 717 | f.debug_struct(name:"PyBorrowMutError" ).finish() |
| 718 | } |
| 719 | } |
| 720 | |
| 721 | impl fmt::Display for PyBorrowMutError { |
| 722 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 723 | fmt::Display::fmt(self:"Already borrowed" , f) |
| 724 | } |
| 725 | } |
| 726 | |
| 727 | impl From<PyBorrowMutError> for PyErr { |
| 728 | fn from(other: PyBorrowMutError) -> Self { |
| 729 | PyRuntimeError::new_err(args:other.to_string()) |
| 730 | } |
| 731 | } |
| 732 | |
| 733 | #[cfg (test)] |
| 734 | #[cfg (feature = "macros" )] |
| 735 | mod 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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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::with_gil(|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 | |