Mercurial > hg
changeset 51213:62e39bef36ca
rust-index: add support for delta-chain computation
author | Raphaël Gomès <rgomes@octobus.net> |
---|---|
date | Thu, 03 Aug 2023 15:50:14 +0200 |
parents | 9b06e7f32bc5 |
children | 050098d60c30 |
files | rust/hg-core/src/revlog/index.rs rust/hg-cpython/src/revlog.rs |
diffstat | 2 files changed, 78 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-core/src/revlog/index.rs Thu Aug 03 15:01:34 2023 +0200 +++ b/rust/hg-core/src/revlog/index.rs Thu Aug 03 15:50:14 2023 +0200 @@ -512,6 +512,50 @@ } } + /// Obtain the delta chain for a revision. + /// + /// `stop_rev` specifies a revision to stop at. If not specified, we + /// stop at the base of the chain. + /// + /// Returns a 2-tuple of (chain, stopped) where `chain` is a vec of + /// revs in ascending order and `stopped` is a bool indicating whether + /// `stoprev` was hit. + pub fn delta_chain( + &self, + rev: Revision, + stop_rev: Option<Revision>, + ) -> Result<(Vec<Revision>, bool), HgError> { + let mut current_rev = rev; + let mut entry = self.get_entry(rev).unwrap(); + let mut chain = vec![]; + while current_rev.0 != entry.base_revision_or_base_of_delta_chain().0 + && stop_rev.map(|r| r != current_rev).unwrap_or(true) + { + chain.push(current_rev); + let new_rev = if self.uses_generaldelta() { + entry.base_revision_or_base_of_delta_chain() + } else { + UncheckedRevision(current_rev.0 - 1) + }; + if new_rev.0 == NULL_REVISION.0 { + break; + } + current_rev = self.check_revision(new_rev).ok_or_else(|| { + HgError::corrupted(format!("Revision {new_rev} out of range")) + })?; + entry = self.get_entry(current_rev).unwrap() + } + + let stopped = if stop_rev.map(|r| current_rev == r).unwrap_or(false) { + true + } else { + chain.push(current_rev); + false + }; + chain.reverse(); + Ok((chain, stopped)) + } + pub fn find_snapshots( &self, start_rev: UncheckedRevision,
--- a/rust/hg-cpython/src/revlog.rs Thu Aug 03 15:01:34 2023 +0200 +++ b/rust/hg-cpython/src/revlog.rs Thu Aug 03 15:50:14 2023 +0200 @@ -310,7 +310,40 @@ /// determine revisions with deltas to reconstruct fulltext def deltachain(&self, *args, **kw) -> PyResult<PyObject> { - self.call_cindex(py, "deltachain", args, kw) + let index = self.index(py).borrow(); + let rev = args.get_item(py, 0).extract::<BaseRevision>(py)?.into(); + let stop_rev = + args.get_item(py, 1).extract::<Option<BaseRevision>>(py)?; + let rev = index.check_revision(rev).ok_or_else(|| { + nodemap_error(py, NodeMapError::RevisionNotInIndex(rev)) + })?; + let stop_rev = if let Some(stop_rev) = stop_rev { + let stop_rev = UncheckedRevision(stop_rev); + Some(index.check_revision(stop_rev).ok_or_else(|| { + nodemap_error(py, NodeMapError::RevisionNotInIndex(stop_rev)) + })?) + } else {None}; + let (chain, stopped) = index.delta_chain(rev, stop_rev).map_err(|e| { + PyErr::new::<cpython::exc::ValueError, _>(py, e.to_string()) + })?; + + let cresult = self.call_cindex(py, "deltachain", args, kw)?; + let cchain: Vec<BaseRevision> = + cresult.get_item(py, 0)?.extract::<Vec<BaseRevision>>(py)?; + let chain: Vec<_> = chain.into_iter().map(|r| r.0).collect(); + assert_eq!(chain, cchain); + assert_eq!(stopped, cresult.get_item(py, 1)?.extract(py)?); + + Ok( + PyTuple::new( + py, + &[ + chain.into_py_object(py).into_object(), + stopped.into_py_object(py).into_object() + ] + ).into_object() + ) + } /// slice planned chunk read to reach a density threshold