changeset 52868:8e94b32de84b

rust-pyo3-dirstate: Dirs methods not involving iterators We hesitated on this one: was it worth it to introduce the `with_inner_*` helpers? Finally quickness and uniformity decided we should. At this point it would be interesting to do something in `pyo3-sharedref` to provide them automatically, but some callers will need the self reference (as in `revlog`), some would not.
author Georges Racinet <georges.racinet@cloudcrane.io>
date Wed, 05 Feb 2025 11:11:05 +0100
parents aa2cfeed65c9
children 8c11ec902e73
files rust/hg-pyo3/src/dirstate/dirs_multiset.rs rust/hg-pyo3/src/dirstate/dirstate_map.rs
diffstat 2 files changed, 69 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-pyo3/src/dirstate/dirs_multiset.rs	Tue Feb 04 19:37:22 2025 +0100
+++ b/rust/hg-pyo3/src/dirstate/dirs_multiset.rs	Wed Feb 05 11:11:05 2025 +0100
@@ -9,15 +9,19 @@
 //! `hg-core` package.
 use pyo3::exceptions::PyTypeError;
 use pyo3::prelude::*;
-use pyo3::types::PyDict;
+use pyo3::types::{PyBytes, PyDict};
 use pyo3_sharedref::PyShareable;
 
-use hg::{dirstate::dirs_multiset::DirsMultiset, utils::hg_path::HgPathBuf};
+use std::sync::{RwLockReadGuard, RwLockWriteGuard};
 
-use crate::exceptions::to_string_value_error;
+use hg::{
+    dirstate::dirs_multiset::DirsMultiset,
+    utils::hg_path::{HgPath, HgPathBuf},
+};
+
+use crate::exceptions::{map_try_lock_error, to_string_value_error};
 
 #[pyclass(mapping)]
-#[allow(dead_code)]
 pub struct Dirs {
     pub(super) inner: PyShareable<DirsMultiset>,
 }
@@ -43,4 +47,63 @@
                 .into(),
         })
     }
+
+    fn addpath(
+        slf: &Bound<'_, Self>,
+        path: &Bound<'_, PyBytes>,
+    ) -> PyResult<()> {
+        let path = HgPath::new(path.as_bytes());
+        Self::with_inner_write(slf, |mut inner| {
+            inner.add_path(path).map_err(to_string_value_error)
+        })
+    }
+
+    fn delpath(
+        slf: &Bound<'_, Self>,
+        path: &Bound<'_, PyBytes>,
+    ) -> PyResult<()> {
+        let path = HgPath::new(path.as_bytes());
+        Self::with_inner_write(slf, |mut inner| {
+            inner.delete_path(path).map_err(to_string_value_error)
+        })
+    }
+
+    fn __contains__(
+        slf: &Bound<'_, Self>,
+        key: &Bound<'_, PyAny>,
+    ) -> PyResult<bool> {
+        let path = if let Ok(k) = key.extract::<&[u8]>() {
+            HgPath::new(k)
+        } else {
+            return Ok(false);
+        };
+
+        Self::with_inner_read(slf, |inner| Ok(inner.contains(path)))
+    }
 }
+
+impl Dirs {
+    pub(super) fn with_inner_read<T>(
+        slf: &Bound<'_, Self>,
+        f: impl FnOnce(RwLockReadGuard<DirsMultiset>) -> PyResult<T>,
+    ) -> PyResult<T> {
+        let self_ref = slf.borrow();
+        // Safety: the owner is the right one. We will anyway
+        // not actually `share` it.
+        let shareable_ref = unsafe { self_ref.inner.borrow_with_owner(slf) };
+        let guard = shareable_ref.try_read().map_err(map_try_lock_error)?;
+        f(guard)
+    }
+
+    pub(super) fn with_inner_write<T>(
+        slf: &Bound<'_, Self>,
+        f: impl FnOnce(RwLockWriteGuard<DirsMultiset>) -> PyResult<T>,
+    ) -> PyResult<T> {
+        let self_ref = slf.borrow();
+        // Safety: the owner is the right one. We will anyway
+        // not actually `share` it.
+        let shareable_ref = unsafe { self_ref.inner.borrow_with_owner(slf) };
+        let guard = shareable_ref.try_write().map_err(map_try_lock_error)?;
+        f(guard)
+    }
+}
--- a/rust/hg-pyo3/src/dirstate/dirstate_map.rs	Tue Feb 04 19:37:22 2025 +0100
+++ b/rust/hg-pyo3/src/dirstate/dirstate_map.rs	Wed Feb 05 11:11:05 2025 +0100
@@ -346,6 +346,8 @@
 
     fn __contains__(
         slf: &Bound<'_, Self>,
+        // TODO we should accept PyAny and return false if wrong type
+        // review similar "protocol" methods (see example in dirs_multiset)
         key: &Bound<'_, PyBytes>,
     ) -> PyResult<bool> {
         Self::with_inner_read(slf, |_self_ref, inner| {