diff rust/hg-pyo3/src/convert_cpython.rs @ 52445:233707101dae

rust-pyo3: simplified API to get core Index references Given the amount of conversion and arcane internal detail, it is easier for the caller and makes a better separation of concerns to just introduce a new unsafe helper. It is actually possible that it would be safe, and we can decide about that later. Actually the reason given in the `cpython` crate for unsafety of the `try_borrow()` method is the following: ``` // try_borrow() and try_borrow_mut() are unsafe because self.data may // have a function returning the inner &'static reference. // If T is &'static U, its lifetime can be easily coerced to &'a U, but // how could we do that for Whatever<'static> in general? ``` Given that we coerce the Index reference to the GIL lifetime and that it is unlikely that the inner data would contain a function returning the a `'static` reference, it is possible that it is actually even safe.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Fri, 29 Nov 2024 23:35:31 +0100
parents c2480ac4c5e2
children 64a618048ba8
line wrap: on
line diff
--- a/rust/hg-pyo3/src/convert_cpython.rs	Sat Nov 30 20:58:09 2024 +0100
+++ b/rust/hg-pyo3/src/convert_cpython.rs	Fri Nov 29 23:35:31 2024 +0100
@@ -16,6 +16,7 @@
 use cpython::PythonObject;
 use lazy_static::lazy_static;
 
+use hg::revlog::index::Index as CoreIndex;
 use rusthg::revlog::{InnerRevlog, PySharedIndex};
 
 /// Force cpython's GIL handle with the appropriate lifetime
@@ -165,9 +166,21 @@
     Ok(unsafe { leaked.map(py, |idx| PySharedIndex { inner: &idx.index }) })
 }
 
-pub(crate) fn proxy_index_extract<'py>(
+/// Full extraction of the proxy index object as received in PyO3 to a
+/// [`CoreIndex`] reference.
+///
+/// The safety invariants to maintain are those of the underlying
+/// [`UnsafePyLeaked::try_borrow`]: the caller must not leak the inner
+/// reference.
+pub(crate) unsafe fn proxy_index_extract<'py>(
     index_proxy: &Bound<'py, PyAny>,
-) -> PyResult<(cpython::Python<'py>, cpython::UnsafePyLeaked<PySharedIndex>)> {
+) -> PyResult<&'py CoreIndex> {
     let (py, idx_proxy) = to_cpython_py_object(index_proxy);
-    Ok((py, py_rust_index_to_graph(py, idx_proxy)?))
+    let py_leaked = py_rust_index_to_graph(py, idx_proxy)?;
+    let py_shared = &*unsafe {
+        py_leaked
+            .try_borrow(py)
+            .map_err(|e| from_cpython_pyerr(py, e))?
+    };
+    Ok(py_shared.inner)
 }