changeset 52555:1dd673c1ab3b

rust-pyo3: getting rust-cpython GIL handle from various PyO3 objects Depending on the caller context, we might have a `Python<'py>` around or any of the smart pointers that bear the GIL lifetime. Of course, all of these can give back a `Python<'py>` but it is worthwile to reduce the needed boilerplate. The trait just expresses that a lifetime is assumed to be outlived by the PyO3 GIL lifetime. It is marked as unsafe because that is just trusting the implementor. A first version of this was made of a safe trait with a `get_py()` method and the corresponding trivial implementations. We found it finally to be even more artificial, as it boils down to coding 4 functions doing and returning no real data, that we hope the compiler will optimize away.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Mon, 09 Dec 2024 09:38:57 +0100
parents 64a618048ba8
children bd65cb043aa5
files rust/hg-pyo3/src/convert_cpython.rs
diffstat 1 files changed, 22 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-pyo3/src/convert_cpython.rs	Sat Dec 07 18:05:47 2024 +0100
+++ b/rust/hg-pyo3/src/convert_cpython.rs	Mon Dec 09 09:38:57 2024 +0100
@@ -11,6 +11,7 @@
 //! the arguments side of function signatures when they are not simply elided.
 use pyo3::exceptions::PyTypeError;
 use pyo3::prelude::*;
+use pyo3::{pyclass::boolean_struct::False, PyClass};
 
 use cpython::ObjectProtocol;
 use cpython::PythonObject;
@@ -19,6 +20,23 @@
 use hg::revlog::index::Index as CoreIndex;
 use rusthg::revlog::{InnerRevlog, PySharedIndex};
 
+/// Marker trait for PyO3 objects with a lifetime representing the acquired GIL
+///
+/// # Safety
+///
+/// This trait must not be implemented for objects with lifetimes that
+/// do not imply in PyO3 that the GIL is acquired during the whole lifetime.
+pub unsafe trait WithGIL<'py> {}
+
+// Safety: the lifetime on these PyO3 objects all represent the acquired GIL
+unsafe impl<'py> WithGIL<'py> for Python<'py> {}
+unsafe impl<'py, T> WithGIL<'py> for Bound<'py, T> {}
+unsafe impl<'py, T: PyClass> WithGIL<'py> for PyRef<'py, T> {}
+unsafe impl<'py, T: PyClass<Frozen = False>> WithGIL<'py>
+    for PyRefMut<'py, T>
+{
+}
+
 /// Force cpython's GIL handle with the appropriate lifetime
 ///
 /// In `pyo3`, the fact that we have the GIL is expressed by the lifetime of
@@ -31,10 +49,11 @@
 /// already has it works) *as long as it is properly released*
 /// reference:
 /// <https://docs.python.org/3.8/c-api/init.html#c.PyGILState_Ensure>
-pub(crate) fn cpython_handle<'py, T>(
-    _bound: &Bound<'py, T>,
+pub(crate) fn cpython_handle<'py, T: WithGIL<'py>>(
+    _with_gil: &T,
 ) -> cpython::Python<'py> {
-    // safety: this is safe because the returned object has the 'py lifetime
+    // safety: this is safe because the returned object has the same lifetime
+    // as the incoming object.
     unsafe { cpython::Python::assume_gil_acquired() }
 }