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.
--- 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| {