rust-index: add support for `headrevsfiltered`
The implementation is merged with that of `headrevs` also to make sure that
caches are up to date.
--- a/rust/hg-core/src/revlog/index.rs Tue Sep 19 15:21:43 2023 +0200
+++ b/rust/hg-core/src/revlog/index.rs Mon Oct 30 11:14:25 2023 +0100
@@ -263,6 +263,9 @@
/// Cache of the head revisions in this index, kept in sync. Should
/// be accessed via the [`Self::head_revs`] method.
head_revs: Vec<Revision>,
+ /// Cache of the last filtered revisions in this index, used to make sure
+ /// we haven't changed filters when returning the cached `head_revs`.
+ filtered_revs: HashSet<Revision>,
}
impl Debug for Index {
@@ -363,6 +366,7 @@
uses_generaldelta,
is_inline: true,
head_revs: vec![],
+ filtered_revs: HashSet::new(),
})
} else {
Err(HgError::corrupted("unexpected inline revlog length"))
@@ -374,6 +378,7 @@
uses_generaldelta,
is_inline: false,
head_revs: vec![],
+ filtered_revs: HashSet::new(),
})
}
}
@@ -520,13 +525,36 @@
/// Return the head revisions of this index
pub fn head_revs(&mut self) -> Result<Vec<Revision>, GraphError> {
- if !self.head_revs.is_empty() {
+ self.head_revs_filtered(&HashSet::new())
+ }
+
+ /// Return the head revisions of this index
+ pub fn head_revs_filtered(
+ &mut self,
+ filtered_revs: &HashSet<Revision>,
+ ) -> Result<Vec<Revision>, GraphError> {
+ if !self.head_revs.is_empty() && filtered_revs == &self.filtered_revs {
return Ok(self.head_revs.to_owned());
}
- let mut revs: HashSet<Revision, RandomState> = (0..self.len())
- .into_iter()
- .map(|i| Revision(i as BaseRevision))
- .collect();
+ let mut revs: HashSet<Revision, RandomState> =
+ if filtered_revs.is_empty() {
+ (0..self.len())
+ .into_iter()
+ .map(|i| Revision(i as BaseRevision))
+ .collect()
+ } else {
+ (0..self.len())
+ .into_iter()
+ .filter_map(|i| {
+ let r = Revision(i as BaseRevision);
+ if filtered_revs.contains(&r) {
+ None
+ } else {
+ Some(r)
+ }
+ })
+ .collect()
+ };
dagops::retain_heads(self, &mut revs)?;
if self.is_empty() {
revs.insert(NULL_REVISION);
@@ -535,6 +563,7 @@
revs.into_iter().map(Into::into).collect();
as_vec.sort_unstable();
self.head_revs = as_vec.to_owned();
+ self.filtered_revs = filtered_revs.to_owned();
Ok(as_vec)
}
--- a/rust/hg-cpython/src/revlog.rs Tue Sep 19 15:21:43 2023 +0200
+++ b/rust/hg-cpython/src/revlog.rs Mon Oct 30 11:14:25 2023 +0100
@@ -7,6 +7,8 @@
use crate::{
cindex,
+ conversion::rev_pyiter_collect,
+ exceptions::GraphError,
utils::{node_from_py_bytes, node_from_py_object},
PyRevision,
};
@@ -259,7 +261,20 @@
/// get filtered head revisions
def headrevsfiltered(&self, *args, **kw) -> PyResult<PyObject> {
- self.call_cindex(py, "headrevsfiltered", args, kw)
+ let rust_res = self.inner_headrevsfiltered(py, &args.get_item(py, 0))?;
+ let c_res = self.call_cindex(py, "headrevsfiltered", args, kw)?;
+ assert_eq!(
+ rust_res.len(),
+ c_res.len(py)?,
+ "filtered heads differ {:?} {}",
+ rust_res,
+ c_res
+ );
+ for (index, rev) in rust_res.iter().enumerate() {
+ let c_rev: BaseRevision = c_res.get_item(py, index)?.extract(py)?;
+ assert_eq!(c_rev, rev.0);
+ }
+ Ok(c_res)
}
/// True if the object is a snapshot
@@ -797,6 +812,19 @@
.collect();
Ok(PyList::new(py, &as_vec).into_object())
}
+
+ fn inner_headrevsfiltered(
+ &self,
+ py: Python,
+ filtered_revs: &PyObject,
+ ) -> PyResult<Vec<Revision>> {
+ let index = &mut *self.index(py).borrow_mut();
+ let filtered_revs = rev_pyiter_collect(py, filtered_revs, index)?;
+
+ index
+ .head_revs_filtered(&filtered_revs)
+ .map_err(|e| GraphError::pynew(py, e))
+ }
}
fn revlog_error(py: Python) -> PyErr {