Add `Py::drop_ref` method (#3871)

* add Py::drop_ref method

* add changelog entry

* fix ffi import

* integrate review feedback

* Add a test

* Fix some build errors

* Fix some more build errors
This commit is contained in:
Juniper Tyree 2024-02-22 00:56:03 +02:00 committed by GitHub
parent 61bc02d927
commit 885883bf68
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 51 additions and 0 deletions

View File

@ -0,0 +1 @@
Add `Py::drop_ref` to explicitly drop a `Py`` and immediately decrease the Python reference count if the GIL is already held.

View File

@ -822,6 +822,10 @@ impl<T> IntoPy<PyObject> for Borrowed<'_, '_, T> {
/// Otherwise, the reference count will be decreased the next time the GIL is
/// reacquired.
///
/// If you happen to be already holding the GIL, [`Py::drop_ref`] will decrease
/// the Python reference count immediately and will execute slightly faster than
/// relying on implicit [`Drop`]s.
///
/// # A note on `Send` and `Sync`
///
/// Accessing this object is threadsafe, since any access to its API requires a [`Python<'py>`](crate::Python) token.
@ -1228,6 +1232,35 @@ impl<T> Py<T> {
unsafe { Py::from_borrowed_ptr(py, self.0.as_ptr()) }
}
/// Drops `self` and immediately decreases its reference count.
///
/// This method is a micro-optimisation over [`Drop`] if you happen to be holding the GIL
/// already.
///
/// Note that if you are using [`Bound`], you do not need to use [`Self::drop_ref`] since
/// [`Bound`] guarantees that the GIL is held.
///
/// # Examples
///
/// ```rust
/// use pyo3::prelude::*;
/// use pyo3::types::PyDict;
///
/// # fn main() {
/// Python::with_gil(|py| {
/// let object: Py<PyDict> = PyDict::new_bound(py).unbind();
///
/// // some usage of object
///
/// object.drop_ref(py);
/// });
/// # }
/// ```
#[inline]
pub fn drop_ref(self, py: Python<'_>) {
let _ = self.into_bound(py);
}
/// Returns whether the object is considered to be None.
///
/// This is equivalent to the Python expression `self is None`.
@ -2142,6 +2175,23 @@ a = A()
})
}
#[test]
fn explicit_drop_ref() {
Python::with_gil(|py| {
let object: Py<PyDict> = PyDict::new_bound(py).unbind();
let object2 = object.clone_ref(py);
assert_eq!(object.as_ptr(), object2.as_ptr());
assert_eq!(object.get_refcnt(py), 2);
object.drop_ref(py);
assert_eq!(object2.get_refcnt(py), 1);
object2.drop_ref(py);
});
}
#[cfg(feature = "macros")]
mod using_macros {
use crate::PyCell;