changeset 52793:6a70e4931773

rust-pyo3-revlog: ReadingContextManager Stepping aside from the implementation of index methods to show that this will not be a problem. The test basically only demonstrates that it behaves like a context manager indeed ? of course our fixture does not provide any reasonable file access.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Mon, 23 Dec 2024 00:17:03 +0100
parents acae91fad6be
children 5ad4ed71fbe0
files rust/hg-pyo3/src/revlog/mod.rs tests/test-rust-revlog.py
diffstat 2 files changed, 49 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-pyo3/src/revlog/mod.rs	Sun Dec 22 17:02:09 2024 +0100
+++ b/rust/hg-pyo3/src/revlog/mod.rs	Mon Dec 23 00:17:03 2024 +0100
@@ -53,6 +53,38 @@
 };
 
 #[pyclass]
+struct ReadingContextManager {
+    inner_revlog: Py<InnerRevlog>,
+}
+
+#[pymethods]
+impl ReadingContextManager {
+    fn __enter__(slf: PyRef<'_, Self>) -> PyResult<()> {
+        let inner_bound = slf.inner_revlog.bind(slf.py());
+        let shareable = &inner_bound.borrow().irl;
+        // Safety: the owner is correct and we won't use `share()` anyway
+        let core_irl =
+            unsafe { shareable.borrow_with_owner(inner_bound) }.read();
+        core_irl
+            .enter_reading_context()
+            .map_err(revlog_error_from_msg)
+            .inspect_err(|_e| {
+                // `__exit__` is not called from Python if `__enter__` fails
+                core_irl.exit_reading_context();
+            })
+    }
+
+    #[pyo3(signature = (*_args))]
+    fn __exit__(slf: PyRef<'_, Self>, _args: &Bound<'_, PyTuple>) {
+        let inner_bound = slf.inner_revlog.bind(slf.py());
+        let shareable = &inner_bound.borrow().irl;
+        // Safety: the owner is correct and we won't use `share()` anyway
+        let core_irl_ref = unsafe { shareable.borrow_with_owner(inner_bound) };
+        core_irl_ref.read().exit_reading_context();
+    }
+}
+
+#[pyclass]
 #[allow(dead_code)]
 struct InnerRevlog {
     irl: PyShareable<CoreInnerRevlog>,
@@ -146,6 +178,12 @@
         })
     }
 
+    fn reading(slf: &Bound<'_, Self>) -> PyResult<ReadingContextManager> {
+        Ok(ReadingContextManager {
+            inner_revlog: slf.clone().unbind(),
+        })
+    }
+
     //
     // -- forwarded index methods --
     //
@@ -575,5 +613,6 @@
     let m = new_submodule(py, package, "revlog")?;
     m.add_class::<InnerRevlog>()?;
     m.add_class::<NodeTree>()?;
+    m.add_class::<ReadingContextManager>()?;
     Ok(m)
 }
--- a/tests/test-rust-revlog.py	Sun Dec 22 17:02:09 2024 +0100
+++ b/tests/test-rust-revlog.py	Mon Dec 23 00:17:03 2024 +0100
@@ -156,6 +156,16 @@
         del idx[3]
         self.assertTrue(nt.is_invalidated())
 
+    def test_reading_context_manager(self):
+        irl = self.make_inner_revlog()
+        try:
+            with irl.reading():
+                # not much to do yet
+                pass
+        except error.RevlogError as exc:
+            # well our data file does not even exist
+            self.assertTrue(b"when reading Just a path/test.d" in exc.args[0])
+
 
 # Conditional skipping done by the base class
 class RustInnerRevlogTest(