Skip to content

Commit

Permalink
Add Py::drop_ref method (#3871)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
juntyr authored Feb 21, 2024
1 parent 61bc02d commit 885883b
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
1 change: 1 addition & 0 deletions newsfragments/3871.added.md
Original file line number Diff line number Diff line change
@@ -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.
50 changes: 50 additions & 0 deletions src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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`.
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit 885883b

Please sign in to comment.