Mercurial > public > mercurial-scm > hg
diff rust/hg-cpython/src/dirstate/status.rs @ 48454:473af5cbc209
rhg: Add support for `rhg status --copies`
Copy sources are collected during `status()` rather than after the fact like
in Python, because `status()` takes a `&mut` exclusive reference to the dirstate map
(in order to potentially mutate it for directory mtimes) and returns `Cow<'_, HgPath>`
that borrow the dirstate map.
Even though with `Cow` only some shared borrows remain, the still extend the same
lifetime of the initial `&mut` so the dirstate map cannot be borrowed again
to access copy sources after the fact:
https://doc.rust-lang.org/nomicon/lifetime-mismatch.html#limits-of-lifetimes
Additionally, collecting copy sources during the dirstate tree traversal that
`status()` already does avoids the cost of another traversal or other lookups
(though I haven?t benchmarked that cost).
Differential Revision: https://phab.mercurial-scm.org/D11899
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Fri, 10 Dec 2021 16:18:58 +0100 |
parents | b80e5e75d51e |
children | 6e930bc45aeb |
line wrap: on
line diff
--- a/rust/hg-cpython/src/dirstate/status.rs Fri Dec 10 16:57:39 2021 +0100 +++ b/rust/hg-cpython/src/dirstate/status.rs Fri Dec 10 16:18:58 2021 +0100 @@ -15,6 +15,7 @@ exc::ValueError, ObjectProtocol, PyBytes, PyErr, PyList, PyObject, PyResult, PyTuple, Python, PythonObject, ToPyObject, }; +use hg::dirstate::status::StatusPath; use hg::{ matchers::{AlwaysMatcher, FileMatcher, IncludeMatcher}, parse_pattern_syntax, @@ -27,15 +28,19 @@ }; use std::borrow::Borrow; +fn collect_status_path_list(py: Python, paths: &[StatusPath<'_>]) -> PyList { + collect_pybytes_list(py, paths.iter().map(|item| &*item.path)) +} + /// This will be useless once trait impls for collection are added to `PyBytes` /// upstream. fn collect_pybytes_list( py: Python, - collection: &[impl AsRef<HgPath>], + iter: impl Iterator<Item = impl AsRef<HgPath>>, ) -> PyList { let list = PyList::new(py, &[]); - for path in collection.iter() { + for path in iter { list.append( py, PyBytes::new(py, path.as_ref().as_bytes()).into_object(), @@ -121,6 +126,8 @@ }) .collect(); let ignore_files = ignore_files?; + // The caller may call `copymap.items()` separately + let list_copies = false; match matcher.get_type(py).name(py).borrow() { "alwaysmatcher" => { @@ -135,6 +142,7 @@ list_clean, list_ignored, list_unknown, + list_copies, collect_traversed_dirs, }, ) @@ -171,6 +179,7 @@ list_clean, list_ignored, list_unknown, + list_copies, collect_traversed_dirs, }, ) @@ -222,6 +231,7 @@ list_clean, list_ignored, list_unknown, + list_copies, collect_traversed_dirs, }, ) @@ -241,16 +251,16 @@ status_res: DirstateStatus, warnings: Vec<PatternFileWarning>, ) -> PyResult<PyTuple> { - let modified = collect_pybytes_list(py, status_res.modified.as_ref()); - let added = collect_pybytes_list(py, status_res.added.as_ref()); - let removed = collect_pybytes_list(py, status_res.removed.as_ref()); - let deleted = collect_pybytes_list(py, status_res.deleted.as_ref()); - let clean = collect_pybytes_list(py, status_res.clean.as_ref()); - let ignored = collect_pybytes_list(py, status_res.ignored.as_ref()); - let unknown = collect_pybytes_list(py, status_res.unknown.as_ref()); - let unsure = collect_pybytes_list(py, status_res.unsure.as_ref()); - let bad = collect_bad_matches(py, status_res.bad.as_ref())?; - let traversed = collect_pybytes_list(py, status_res.traversed.as_ref()); + let modified = collect_status_path_list(py, &status_res.modified); + let added = collect_status_path_list(py, &status_res.added); + let removed = collect_status_path_list(py, &status_res.removed); + let deleted = collect_status_path_list(py, &status_res.deleted); + let clean = collect_status_path_list(py, &status_res.clean); + let ignored = collect_status_path_list(py, &status_res.ignored); + let unknown = collect_status_path_list(py, &status_res.unknown); + let unsure = collect_status_path_list(py, &status_res.unsure); + let bad = collect_bad_matches(py, &status_res.bad)?; + let traversed = collect_pybytes_list(py, status_res.traversed.iter()); let dirty = status_res.dirty.to_py_object(py); let py_warnings = PyList::new(py, &[]); for warning in warnings.iter() {